-- 自己房卡游戏逻辑模块

local skynet = require "skynet"
local base = require "base"
local timetool = require "timetool"
local timer = require "timer"
local filelog = require "filelog"
local cardtool = require "mjexcardtool"
local tabletool = require "tabletool"
local configdao = require "configdao"
local slottool = require "slottool"

require "mjexenum"

local GameLogic = { }
local service = nil
local tablelogic = nil
local seatlogic = nil

--[Comment]
--init 初始化
function GameLogic.init(caller)
	service = caller
	tablelogic = service:get_logicbyname("tablelogic")
	seatlogic = service:get_logicbyname("seatlogic")
end

--[Comment]
--初始化数据,主要设置游戏状态事件对应的函数
--
function GameLogic.init_data(gameobj, tableobj)
	gameobj.tableobj = tableobj
	gameobj.stateevent[EMJTableState.TABLE_STATE_GAME_START] =  GameLogic.gamestart                         --游戏开始
    gameobj.stateevent[EMJTableState.TABLE_STATE_GAME_END] = GameLogic.gameend                              --游戏结束
    gameobj.stateevent[EMJTableState.TABLE_STATE_DISBAND_GAME] = GameLogic.disbandgame                      --解散游戏
	gameobj.stateevent[EMJTableState.TABLE_STATE_ONE_GAME_START] = GameLogic.onegamestart                   --一局游戏开始
	gameobj.stateevent[EMJTableState.TABLE_STATE_ONE_GAME_END] = GameLogic.onegameend                       --一局游戏结束
	gameobj.stateevent[EMJTableState.TABLE_STATE_ONE_GAME_REAL_END] = GameLogic.onegamerealend              --一局游戏真正结束

	gameobj.stateevent[EMJTableState.TABLE_STATE_CONTINUE] = GameLogic.continue                             --继续执行操作
	gameobj.stateevent[EMJTableState.TABLE_STATE_CONTINUE_AND_STANDUP] = GameLogic.continue_and_standup     --收到客户端确认后，继续执行站起操作
	gameobj.stateevent[EMJTableState.TABLE_STATE_CONTINUE_AND_LEAVE] = GameLogic.continue_and_leave         --收到客户端确认后，继续执行离桌操作

	gameobj.stateevent[EMJTableState.TABLE_STATE_MJ_DEAL_CARDS] = GameLogic.deal_cards                          --给玩家发牌

	gameobj.stateevent[EMJTableState.TABLE_STATE_MJ_DO_MOPAI] = GameLogic.do_mopai	                            --通知摸牌
    gameobj.stateevent[EMJTableState.TABLE_STATE_MJ_DO_REAL_MOPAI] = GameLogic.do_real_mopai	                --真正摸牌
	gameobj.stateevent[EMJTableState.TABLE_STATE_MJ_MOPAI] = GameLogic.action_type_mopai                        --处理摸牌结果,通知玩家出牌

	gameobj.stateevent[EMJTableState.TABLE_STATE_MJ_CHUPAI] = GameLogic.action_type_chupai                      --处理玩家出牌，通知其他玩家出牌结果
	gameobj.stateevent[EMJTableState.TABLE_STATE_MJ_HUPAI] = GameLogic.on_action_type_hupai                     --处理玩家胡牌操作
    gameobj.stateevent[EMJTableState.TABLE_STATE_DEAL_BANKER_FIRST_ACTION] = GameLogic.deal_banker_firstaction  --庄家第一次操作

    gameobj.stateevent[EMJTableState.TABLE_STATE_MJ_SHAKE_DICE] = GameLogic.shake_dice                      --通知玩家摇骰子
    gameobj.stateevent[EMJTableState.TABLE_STATE_CONTINUE_HUANSANZHANG] = GameLogic.continue_huansanzhang   --收到客户端确认后，继续执行换三张操作
	gameobj.stateevent[EMJTableState.TABLE_STATE_CONTINUE_DINGQUE] = GameLogic.continue_dingque             --收到客户端确认后，继续执行定缺操作
   
	gameobj.stateevent[EMJTableState.TABLE_STATE_MJ_DINGQUE] = GameLogic.ding_que                           --通知玩家定缺 
    gameobj.stateevent[EMJTableState.TABLE_STATE_MJ_HUAN_SAN_ZHANG] = GameLogic.huan_san_zhang              --通知玩家换三张

    --gameobj.stateevent[EMJTableState.TABLE_STATE_MJ_CHA_DA_JIAO] = GameLogic.do_cha_da_jiao                 --查大叫

    --初始化服务费
    tableobj.service_fee = GameLogic.get_service_fee(tableobj)

    --初始化游戏记录
    GameLogic.init_game_records(tableobj)

	return true
end

--[Comment]
-- 运行游戏，不断执行状态事件,外部接口
--
function GameLogic.run(gameobj)
	local f = nil
	while true do
        --如果未全部准备，退出
		if gameobj.tableobj.state == EMJTableState.TABLE_STATE_WAIT_ALL_READY then
			break
		end

		f = gameobj.stateevent[gameobj.tableobj.state]  --获得桌子状态对应方法
		if f == nil then
			break
		end
		f(gameobj)  --执行

        --更新心跳时间
        tablelogic.update_table_heart_time(gameobj.tableobj)
	end
end

---------------------------------------------------------
---------------------------------------------------------
--游戏逻辑处理函数
--

--[Comment]
-- TABLE_STATE_GAME_START
-- 游戏开始
-- 游戏开始---一局游戏开始---游戏----一局游戏结束---准备----一局游戏开始---游戏--一局游戏结束--...--游戏结束
-- gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.gamestart(gameobj)
	local tableobj = gameobj.tableobj

	GameLogic.gamestart_inittable(gameobj)
	tableobj.state = EMJTableState.TABLE_STATE_ONE_GAME_START
    --执行完后将调用onegamestart

	--设置桌子已经开局
	tableobj.is_had_start = true
end

--[Comment]
--  一局游戏开始
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.onegamestart(gameobj)
	local tableobj = gameobj.tableobj

    --一初始化游戏
	GameLogic.onegamestart_inittable(gameobj)

    --当前局数 + 1
	tableobj.curr_to_num = tableobj.curr_to_num + 1	

	--获得随机牌堆
    tableobj.cards_stack = tableobj.cards_stack or { }
	tableobj.cards_stack.cards = cardtool.rand_card_list(tableobj.conf.max_player_num)
	
	--确定庄家位置：1、上局赢家做庄 2、流局上局庄家继续做庄 3、随机位置
    --banker_seat_index     庄家位置
    --last_ypdx_seat_index  上局一炮多响玩家位置（杠后出牌导致多人胡牌的玩家）
    --last_hupai_seat_index 上局胡牌玩家位置
    --last_banker_seat_index上局庄家位置
    --
	if tableobj.last_ypdx_seat_index ~= 0 then
		tableobj.banker_seat_index = tableobj.last_ypdx_seat_index
	elseif tableobj.last_hupai_seat_index ~= 0 then
		tableobj.banker_seat_index = tableobj.last_hupai_seat_index
	elseif tableobj.last_banker_seat_index ~= 0 then
		tableobj.banker_seat_index = tableobj.last_banker_seat_index
	else
		tableobj.banker_seat_index = base.get_random(1, tableobj.conf.max_player_num)
	end
	tableobj.last_hupai_seat_index = 0
	tableobj.last_ypdx_seat_index = 0
    tableobj.last_banker_seat_index = 0

    --暂时固定庄家位置
    --tableobj.banker_seat_index = 1
    tableobj.seats[tableobj.banker_seat_index].is_banker = true

    --初始化牌局记录
    GameLogic.onegamestart_init_tablerecord(gameobj)
    tablelogic.save_playback_record(nil,tableobj.game_records,true)

    --钻石场收取服务费
    if tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI 
    or tableobj.conf.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
        --GameLogic.charge_service_fee(gameobj)
    end

    --钻石场保存初始钻石数
    tableobj.init_diamond_list = { }
    tableobj.win_diamond_limits = { }
    tableobj.curr_seats_money = { }
    for _,seat in pairs(tableobj.seats) do
        if tableobj.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI then
            tableobj.init_diamond_list[seat.rid] = seat.playerinfo.diamond
            tableobj.win_diamond_limits[seat.rid] = seat.playerinfo.diamond
        elseif tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
            tableobj.init_diamond_list[seat.rid] = seat.playerinfo.diamond + seat.playerinfo.coin
            tableobj.win_diamond_limits[seat.rid] = seat.playerinfo.diamond + seat.playerinfo.coin
        elseif tableobj.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
            tableobj.init_diamond_list[seat.rid] = seat.playerinfo.dou
            tableobj.win_diamond_limits[seat.rid] = seat.playerinfo.dou
        else
            tableobj.init_diamond_list[seat.rid] = 0
            tableobj.win_diamond_limits[seat.rid] = 0
        end
        tableobj.curr_seats_money[seat.rid] = {
            diamond = seat.playerinfo.diamond,
            coin = seat.playerinfo.coin,
        }
    end

    --通知client游戏开始
	GameLogic.send_gamestart_notice(gameobj)

    --倒计时等待游戏开始
	tableobj.state = EMJTableState.TABLE_STATE_ONE_WAIT_GAME_START
	local timer_id = timer.settimer(tableobj.countdown_time * 100, "one_game_start")	
	if tableobj.state ~= EMJTableState.TABLE_STATE_ONE_WAIT_GAME_START then
		timer.cleartimer(timer_id)
	else
		tableobj.timer_id = timer_id
	end
end

--[Comment]
--  收取服务费,或房卡
--
function  GameLogic.charge_service_fee(gameobj)
    local tableobj = gameobj.tableobj
    local service_charge = 0
    local is_zuanshi = false
    local is_jinbi = false
    local rid_to_index = { }

    if tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then   --自建房卡，收房卡
        if tableobj.conf.retain_to_num == 4 then
            service_charge = 200
        elseif tableobj.conf.retain_to_num == 8 then
            service_charge = 400
        end
    elseif tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI then  --自建钻石扣钻石
        service_charge = GameLogic.get_service_fee(tableobj)
        is_zuanshi = true
    elseif tableobj.conf.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then    --自金币场扣金币
        service_charge = GameLogic.get_service_fee(tableobj)
        is_jinbi = true
    end

    if service_charge == 0 then
        return
    end

    local rid_values = { }
    for i,seat in pairs(tableobj.seats) do
        rid_values[seat.rid] = {}
        rid_values[seat.rid].value = 0
        rid_values[seat.rid].rolename = seat.playerinfo.rolename
        if is_zuanshi then
            rid_values[seat.rid].beginvalue = seat.playerinfo.diamond
        elseif is_jinbi then
            rid_values[seat.rid].beginvalue = seat.playerinfo.coin
        else
            rid_values[seat.rid].beginvalue = seat.playerinfo.coin
        end
        rid_to_index[seat.rid] = i
    end

    --初始化非空桌位，收取服务费
	for  _, seat in pairs(tableobj.seats) do
		if not seatlogic.is_empty(seat) then
			--收取玩家服务费
			if service_charge > 0 then
                if tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then
                    if tableobj.conf.card_cost_type ~= nil and tableobj.conf.card_cost_type ~= 1 then   --AA制
                        rid_values[seat.rid].value = math.floor(service_charge / tableobj.conf.max_player_num)
                    elseif seat.rid == tableobj.create_rid then  --房主全出
                        rid_values[seat.rid].value = service_charge
                        break	
                    end
                else
                    rid_values[seat.rid].value = service_charge
                end	
			end
		end
	end

    --设置扣除之后的值
    for rid,rv in pairs(rid_values) do
        if rv.value == 0 then   
            rid_values[rid] = nil
        else
            rv.endvalue = rv.beginvalue - rv.value
        end
    end

    --通知gate去扣费
    local status = true
    if is_zuanshi then
        status = tablelogic.game_sub_fuwufei(rid_values)
    elseif is_jinbi then
        status = tablelogic.game_sub_coin(rid_values)
    else
        status = tablelogic.game_sub_fangka(rid_values)
    end
    if not status then
        filelog.sys_error("charge service fee failed!")
        return false
    else
        filelog.sys_info("charge service fee ok!")
    end

    --扣费成功，修改数据
    local noticemsg = { }
    noticemsg.money_change_list = { }
    for rid,rv in pairs(rid_values) do
        local item = { --保存变化
            rid = rid,
        }

        local tmpseat = tableobj.seats[rid_to_index[rid]]
        if is_zuanshi then
            tmpseat.playerinfo.diamond = tmpseat.playerinfo.diamond - rv.value
            item.money_type = EMoneyType.DIAMOND
        elseif is_jinbi then
            tmpseat.playerinfo.coin = tmpseat.playerinfo.coin - rv.value
            item.money_type = EMoneyType.COIN or 3
        else    --房卡也扣金豆
           tmpseat.playerinfo.coin = tmpseat.playerinfo.coin - rv.value
           item.money_type = EMoneyType.COIN
        end
        item.change_value = -rv.value
        item.final_value = rv.endvalue
        table.insert( noticemsg.money_change_list,item)
    end

    --通知客户端已收服务费消息
    --tablelogic.sendmsg_to_alltableplayer(tableobj,"moneychangeN",noticemsg)

    return true
end

--[Comment]
--  摇骰子
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.shake_dice(gameobj)
	local tableobj = gameobj.tableobj
	tableobj.dice_one = base.get_random(1, 6)   --获得随机点数1
	tableobj.dice_two = base.get_random(1, 6)   --获得随机点数2

	--通知client摇骰子
	GameLogic.send_shakedice_notice(gameobj)

    --设置桌子状态为摇骰子
	tableobj.state = EMJTableState.TABLE_STATE_WAIT_MJ_SHAKE_DICE

    --倒计时等待客户端摇骰子
	local timer_id = timer.settimer(3 * 100, "shake_dice")	
	if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_MJ_SHAKE_DICE then
		timer.cleartimer(timer_id)
	else
		tableobj.timer_id = timer_id
	end

    --保存游戏记录
    table.insert(tableobj.game_records.dices_num_list,tableobj.dice_one)
    table.insert(tableobj.game_records.dices_num_list,tableobj.dice_two)
    tablelogic.save_playback_record(tableobj.game_records.dices_num_list)
end

--[Comment]
--  发牌，发到每个座位（服务器发好后，再发给客户端）
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.deal_cards(gameobj)
	local tableobj = gameobj.tableobj
	
	--给玩家发手牌
	local index = 0
	local seat = nil
    local dice_one,dice_two = tableobj.dice_one, tableobj.dice_two
    local allcards = cardtool.deal_cards(tableobj.cards_stack,dice_one,dice_two,tableobj.conf.max_player_num,tableobj.is_7zhang)
	for i = 0, tableobj.conf.max_player_num - 1 do
        --获得座位
		index = (tableobj.banker_seat_index + i) % tableobj.conf.max_player_num
        if index == 0 then
            index = tableobj.conf.max_player_num
        end
		seat = tableobj.seats[index]
		seat.cards = allcards[i+1]
        
        --保存手牌记录
        tableobj.game_records.player_init_cards_list[seat.rid] = tabletool.deepcopy(seat.cards)
	end 	
    --保存记录
    tablelogic.save_playback_record(tableobj.game_records.player_init_cards_list)		

    --通知客户端
	GameLogic.send_dealcards_notice(gameobj)

    --设置桌子状态为：等待发牌
	tableobj.state = EMJTableState.TABLE_STATE_WAIT_MJ_DEAL_CARDS

    --倒计时等待
	local timer_id = timer.settimer(200, "deal_cards")	
	if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_MJ_DEAL_CARDS then
		timer.cleartimer(timer_id)
	else
		tableobj.timer_id = timer_id
	end
end

--[Comment]
--  换三张
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.huan_san_zhang(gameobj)
    local tableobj = gameobj.tableobj
    local out_time = 10
    tableobj.action_timeout_time = timetool.get_time() + out_time

    for _,seat in pairs(tableobj.seats) do
        local t = cardtool.get_exchange_cards(seat.cards)
        local noticemsg = {
            rid = seat.rid,
            seat_index = seat.index,
            suggest_cards = t,
            action_timeout_time = tableobj.action_timeout_time,
        }
        tableobj.huansanzhang_list[seat.index] = tabletool.deepcopy(t)
        tablelogic.sendmsg_to_tableplayer(seat.rid,"huansanzhangN",noticemsg)
    end
    
    tableobj.state = EMJTableState.TABLE_STATE_WAIT_MJ_HUAN_SAN_ZHANG
    local timer_id = timer.settimer(out_time * 100,"huan_san_zhang")
    if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_MJ_HUAN_SAN_ZHANG then
        timer.cleartimer(timer_id)
    else
        tableobj.timer_id = timer_id
    end
end

--[Comment]
--  继续执行换三张操作
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.continue_huansanzhang(gameobj)
	local tableobj = gameobj.tableobj
    local r = base.get_random(0,2)

    if tableobj.huansanzhang_list == nil then
        return
    end

    --删除牌
    for i,tmp_cards in pairs(tableobj.huansanzhang_list) do
        local tmpseat = tableobj.seats[i]
        cardtool.delete_cards(tmpseat.cards,tmp_cards,tmpseat.rid)
    end
    
    local tmp = tabletool.deepcopy(tableobj.huansanzhang_list)
    tableobj.huansanzhang_list = { }
    if r == 0 then      --顺时针换牌
        tableobj.huansanzhang_list[1] = tmp[2]
        tableobj.huansanzhang_list[2] = tmp[3]
        tableobj.huansanzhang_list[3] = tmp[4]
        tableobj.huansanzhang_list[4] = tmp[1]
    elseif r == 1 then  --逆时针换牌
        tableobj.huansanzhang_list[1] = tmp[4]
        tableobj.huansanzhang_list[2] = tmp[1]
        tableobj.huansanzhang_list[3] = tmp[2]
        tableobj.huansanzhang_list[4] = tmp[3]
    else                --对家换牌
        tableobj.huansanzhang_list[1] = tmp[3]
        tableobj.huansanzhang_list[2] = tmp[4]
        tableobj.huansanzhang_list[3] = tmp[1]
        tableobj.huansanzhang_list[4] = tmp[2]
    end

    --插入牌
    for i,tmp_cards in pairs(tableobj.huansanzhang_list) do
        local tmpseat = tableobj.seats[i]
        cardtool.insert_cards(tmpseat.cards,tmp_cards,tmpseat.rid)
    end

    --通知换三张结果
    for i = 1,#(tableobj.seats)  do
        local noticemsg = {
            rid = tableobj.seats[i].rid,
            seat_index = tableobj.seats[i].index,
            select_cards = tmp[i],
            exchange_cards = tabletool.deepcopy(tableobj.huansanzhang_list[i]),
            exchange_type = r,
        }
        tablelogic.sendmsg_to_tableplayer(tableobj.seats[i].rid,"huansanzhangresultN",noticemsg)
        --保存游戏记录
        tableobj.game_records.all_player_huansanzhang_list[noticemsg.rid] = tabletool.deepcopy(tableobj.huansanzhang_list[i])
    end
    tableobj.game_records.all_player_huansanzhang_list.exchange_type = r
    tablelogic.save_playback_record(tableobj.game_records.all_player_huansanzhang_list)

    tableobj.state = EMJTableState.TABLE_STATE_WAIT_MJ_DINGQUE
    local timer_id = timer.settimer(400,"do_ding_que")
    if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_MJ_DINGQUE then
        timer.cleartimer(timer_id)
    else
        tableobj.timer_id = timer_id
    end
    tableobj.huansanzhang_list = nil
end

--[Comment]
--  定缺
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.ding_que(gameobj)
	local tableobj = gameobj.tableobj
    local out_time = 10
    tableobj.action_timeout_time = timetool.get_time() + out_time

    for _,seat in pairs(tableobj.seats) do
        local que_color = cardtool.get_suggest_que(seat.cards)
        local noticemsg = {
            rid = seat.rid,
            seat_index = seat.index,
            suggest_que_color = que_color + 1,
            action_timeout_time = tableobj.action_timeout_time,
        }
        tableobj.que_color_list[seat.index] = que_color
        tablelogic.sendmsg_to_tableplayer(seat.rid,"dingqueN",noticemsg)
    end
    
    tableobj.state = EMJTableState.TABLE_STATE_WAIT_MJ_DINGQUE
    local timer_id = timer.settimer(out_time * 100,"ding_que")
    if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_MJ_DINGQUE then
        timer.cleartimer(timer_id)
    else
        tableobj.timer_id = timer_id
    end
end

--[Comment]
--  继续执行定缺操作
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.continue_dingque(gameobj)
	local tableobj = gameobj.tableobj

    --通知定缺结果
    local noticemsg = {
       que_color_list = { },
    }
    for _,qc in pairs(tableobj.que_color_list) do
        table.insert(noticemsg.que_color_list, qc + 1)
    end
    
    tablelogic.sendmsg_to_alltableplayer(tableobj,"dingqueresultN",noticemsg)
    tableobj.que_color_list = nil

    --保存游戏记录
    for _,seat in pairs(tableobj.seats) do
        tableobj.game_records.player_que_card_color_list[seat.rid] = seat.que_cardcolor or ""
    end 
    tablelogic.save_playback_record(tableobj.game_records.player_que_card_color_list)

    --倒计时等待
    tableobj.state = EMJTableState.TABLE_STATE_WAIT_DINGQUE_RESULT
    local timer_id = timer.settimer(300,"wait_banker_action")
    if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_DINGQUE_RESULT then
        timer.cleartimer(timer_id)
    else
        tableobj.timer_id = timer_id
    end
end

--[Comment]
--  庄家首先操作（摸牌后出牌）
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.deal_banker_firstaction(gameobj)
	local tableobj = gameobj.tableobj
	local noticemsg = nil
	local gang_cards = nil
	local player_action = nil
	local tmp = nil
    local cur_action_type = nil

    --二人麻将缺万
    if tableobj.conf.max_player_num == 2 then
        for _,curseat in pairs(tableobj.seats) do
            curseat.que_cardcolor = EMJCardColorType.CARD_COLOR_WAN
        end 
    end

	seat = tableobj.seats[tableobj.banker_seat_index]
    
	--设置当前的操作到期时间,单位s
    local out_time = (tableobj.conf.action_timeout or 20)
	tableobj.action_timeout_time = timetool.get_time() + out_time

	--记录麻将中当前操作玩家座位号，方便计算下一位操作玩家
	tableobj.curr_action_seat_index = seat.index

	--通知所有玩家等待庄家出牌，client展现操作玩家
	noticemsg = {
		rid = seat.rid,
		seat_index = seat.index,
		action_timeout_time = tableobj.action_timeout_time,
		wait_action_type = EMJActionType.MJ_ACTION_TYPE_CHUPAI,
        remain_card_num = tableobj.cards_stack.cur_num,
	}

    --通知客户端
	tablelogic.sendmsg_to_otheralltableplayer(tableobj,seat.rid,"todoN", { todo_list = {noticemsg}})

    --保存牌局记录

    ------------
    --处理庄家牌，并给庄家发消息
	noticemsg = {
		rid = seat.rid,
		seat_index = seat.index,
		action_timeout_time = tableobj.action_timeout_time,
        remain_card_num = tableobj.cards_stack.cur_num,
        wait_action_types = { },
	}

	tableobj.chu_mo_pai_seat_index = tableobj.banker_seat_index

    --出摸牌类型
	tableobj.chu_mo_paitag = EMJActionType.MJ_ACTION_TYPE_MOPAI 
	tableobj.chu_mo_pai_card = seat.cards[#(seat.cards)]


    --判断庄家是否可以胡牌
    local is_hu,fan_types = cardtool.check_hu(seat.cards,{},nil,true,0,seat.que_cardcolor,tableobj.is_7zhang)
    if is_hu then
        seat.fan_types = fan_types
		table.insert(noticemsg.wait_action_types,EMJActionType.MJ_ACTION_TYPE_HUPAI)		
        cur_action_type = EMJActionType.MJ_ACTION_TYPE_SELECT
    end

	local is_can_gang = false
	gang_cards = cardtool.get_gang_cards(seat.cards,seat.que_cardcolor)
	if #gang_cards > 0 then
		is_can_gang = true
	end

	if is_can_gang then
		--庄家报叫以后开始时不能暗杠手上的牌
        table.insert(noticemsg.wait_action_types,EMJActionType.MJ_ACTION_TYPE_ANGANG)	
        cur_action_type = EMJActionType.MJ_ACTION_TYPE_SELECT
    end

    if #noticemsg.wait_action_types > 0 then    --可以胡或则杠
        table.insert(noticemsg.wait_action_types,EMJActionType.MJ_ACTION_TYPE_GUO)
	else
		--通知庄家出牌
		noticemsg.wait_action_types = {
			EMJActionType.MJ_ACTION_TYPE_CHUPAI,
		}
		--记录出牌位置
		tableobj.chu_mo_pai_seat_index = tableobj.banker_seat_index
		tableobj.chu_mo_paitag = EMJActionType.MJ_ACTION_TYPE_CHUPAI 	
        cur_action_type = EMJActionType.MJ_ACTION_TYPE_CHUPAI			
	end

	if tableobj.action_player_list == nil then
		tableobj.action_player_list = {}
	end

	player_action = { }
    player_action.rid = noticemsg.rid
    player_action.seat_index = noticemsg.seat_index
    player_action.wait_action_types = tabletool.deepcopy(noticemsg.wait_action_types)
	player_action.action_state = EMJActionState.NODO
	player_action.action_type = cur_action_type	
	tableobj.action_player_list[seat.rid] = player_action

	tableobj.state = EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION
    tableobj.curr_actionplayer_rid = seat.rid
	if seat.is_tuoguan then
		local timermsg = {rid=seat.rid, index=seat.index}	
        local tuoguan_time = tableobj.do_tuoguan_time * 100 + base.get_random(1,35) * 3	
		local timerid = timer.settimer(tuoguan_time, "tuoguan_doaction", timermsg)
		if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION 
			or tableobj.action_player_list[timermsg.rid] == nil then
			timer.cleartimer(timerid)
		else
			seat.tuoguan_doaction_timerid = timerid
		end
	end
    --通知庄家出牌
	tablelogic.sendmsg_to_tableplayer(seat.rid, "todoN", { todo_list = {noticemsg}})

    if cur_action_type == EMJActionType.MJ_ACTION_TYPE_SELECT then
            --倒计时等待
	    local timer_id = timer.settimer(tableobj.do_select_timeout * 100, "do_select")	
	    if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION then
		    timer.cleartimer(timer_id)
	    else
		    tableobj.timer_id = timer_id
	    end
    else
        --倒计时等待出牌
	    local timer_id = timer.settimer(out_time * 100, "doaction")	
	    if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION then
		    timer.cleartimer(timer_id)
	    else
		    tableobj.timer_id = timer_id
	    end
        tableobj.chu_mo_pai_card = seat.cards[#(seat.cards)]
    end
end

-----------------------------------------------------------------
--处理：出牌、杠、碰、胡、过

--[Comment]
--  继续执行操作(客户端已经操作)
-- 发牌之后的，出牌、碰、杠、胡、过都由该方法处理
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.continue(gameobj)
	local tableobj = gameobj.tableobj

    --判断其他玩家是否都操作结束
	local is_end,max_had_action = GameLogic.check_end_action(gameobj)
	local player_action = tableobj.action_player_list[tableobj.curr_actionplayer_rid]	

    --设置操作状态为操作中
    if player_action ~= nil then
	    player_action.action_state = EMJActionState.DOING
    else
        player_action = max_had_action
    end

    --保存操作到游戏记录
    if not tableobj.game_records.all_player_action_list then
        tableobj.game_records.all_player_action_list = { }
    end
    local action_list = tableobj.game_records.all_player_action_list
    local action_time = timetool.get_time()
    local is_outtime = false
    if action_time >= tableobj.action_timeout_time then
        is_outtime = true
    end
    
    --处理过手胡
    GameLogic.handle_guo_hu(tableobj,player_action)
    --保存记录
    local item = tostring(action_time) .. "_" .. player_action.rid .. "_" .. player_action.action_type .. "_"
    if player_action.action_type == EMJActionType.MJ_ACTION_TYPE_ANGANG
    or player_action.action_type == EMJActionType.MJ_ACTION_TYPE_BAGANG then
        item = item .. tableobj.curr_actionplayer_cards[1]
    else
        item = item .. tableobj.chu_mo_pai_card
    end
    if is_outtime then
        item = item .. "_" .. "true"
    end
    table.insert(action_list,item)
    tablelogic.save_playback_record(item)

    --其他玩家操作未结束，等待其他玩家操作，直接返回
	if not is_end then
        --设置状态为：等待客户端操作
		tableobj.state = EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION
		return
	end

    --获得座位
	local seat = tableobj.seats[player_action.seat_index]

    --出牌,出牌只会同时有一个操作
	if player_action.action_type == EMJActionType.MJ_ACTION_TYPE_CHUPAI 
     or player_action.action_type == EMJActionType.MJ_ACTION_TYPE_GANG_CHUPAI then
		GameLogic.on_action_type_chupai(gameobj, seat, player_action)
        return
	end

    --以下都可能同时有多个操作
    local max_had_action_type = max_had_action.action_type
    local player_action = max_had_action
    seat = tableobj.seats[max_had_action.seat_index]
    
    --过牌
	if max_had_action_type == EMJActionType.MJ_ACTION_TYPE_GUO then
		GameLogic.on_action_type_guopai(gameobj,seat, player_action)
		return
	end

    --碰牌
	if max_had_action_type == EMJActionType.MJ_ACTION_TYPE_PENG then
		GameLogic.on_action_type_pengpai(gameobj,seat, player_action)
		return		
	end

    --暗杠
	if max_had_action_type == EMJActionType.MJ_ACTION_TYPE_ANGANG then
		GameLogic.on_action_type_angang(gameobj,seat, player_action)
		return		
	end

    --明杠
	if max_had_action_type == EMJActionType.MJ_ACTION_TYPE_ZHIGANG then
		GameLogic.on_action_type_minggang(gameobj,seat, player_action)
		return		
	end

    --弯杠（补杠）
	if max_had_action_type == EMJActionType.MJ_ACTION_TYPE_BAGANG then
		GameLogic.on_action_type_wangang(gameobj,seat, player_action)
		return		
	end

    --胡牌
	if max_had_action_type == EMJActionType.MJ_ACTION_TYPE_HUPAI then
		GameLogic.on_action_type_hupai(gameobj,seat, player_action)
		return		
	end
end

--[Comment]
--  处理过胡操作
--  player_action 玩家操作列表
--
function GameLogic.handle_guo_hu(tableobj,player_action)
    if player_action == nil then
        return
    end

    if player_action.action_type == EMJActionType.MJ_ACTION_TYPE_GUO 
    or player_action.action_type == EMJActionType.MJ_ACTION_TYPE_SELECT then
        if tableobj.chu_mo_pai_seat_index ~= player_action.seat_index then
            for _,action_type in pairs(player_action.wait_action_types) do
		        if action_type == EMJActionType.MJ_ACTION_TYPE_HUPAI then
                    local cur_seat = tableobj.seats[player_action.seat_index]
                    cur_seat.guohu_seat_index = cur_seat.index
                    cur_seat.guohu_max_fan = cur_seat.fan_types[cur_seat.fan_types.max_type]
                    if cur_seat.guohu_cards == nil then
                        cur_seat.guohu_cards = { }
                    end
                    cur_seat.is_guohu = true
                    cur_seat.fan_types = {}
                    table.insert(cur_seat.guohu_cards,tableobj.chu_mo_pai_card)
                    break
                end
            end
        end
    end
end

--[Comment]
--  处理选择超时
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.handler_select_timeout(gameobj)
    local tableobj = gameobj.tableobj
    tableobj.action_player_list = tableobj.action_player_list or { }
    for _,cur_player_action in pairs(tableobj.action_player_list) do
        if cur_player_action.action_type == EMJActionType.MJ_ACTION_TYPE_SELECT then
            local seat = tableobj.seats[cur_player_action.seat_index]
            seat.is_tuoguan = true  --超时自动托管
            seat.in_tuoguan = true
            --通知客户端托管
            local noticemsg = {
		        rid = seat.rid,
		        seat_index = seat.index,	
                is_tuoguan = seat.is_tuoguan,
	        }
            tablelogic.sendmsg_to_alltableplayer(tableobj,"dotuoguanN", noticemsg)
            local cur_time = timetool.get_time()
            local item = "" .. cur_time .. "_" .. seat.rid .. "_" .. "start_tuoguan"
            tablelogic.save_playback_record(item)

            GameLogic.dotuoguan(gameobj, seat)   --托管处理
        end
    end
end

--[Comment]
--  处理出牌超时
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.handler_chupai_timeout(gameobj)
    local tableobj = gameobj.tableobj
    local seat = tableobj.seats[tableobj.chu_mo_pai_seat_index]
    seat.is_tuoguan = true  --超时自动托管
    seat.in_tuoguan = true

    --通知客户端托管
    local noticemsg = {
		rid = seat.rid,
		seat_index = seat.index,	
        is_tuoguan = seat.is_tuoguan,
	}
    tablelogic.sendmsg_to_alltableplayer(tableobj,"dotuoguanN", noticemsg)
    local cur_time = timetool.get_time()
    local item = "" .. cur_time .. "_" .. seat.rid .. "_" .. "start_tuoguan"
    tablelogic.save_playback_record(item)

    GameLogic.dotuoguan(gameobj, seat)   --托管处理
end

------------------------------------------------------------------------------
--核心操作：出牌、杠、碰、胡、过
--

---------------------------
--摸牌

--[Comment]
--  摸牌,只为了做个延迟
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.do_mopai(gameobj)
    local tableobj = gameobj.tableobj
    --local timerid = timer.settimer(30,"do_real_mopai")
    --tableobj.timer_id = timerid
    --tableobj.state = EMJTableState.TABLE_STATE_MJ_WAIT_DO_REAL_MOPAI
    tableobj.state = EMJTableState.TABLE_STATE_MJ_DO_REAL_MOPAI
end

--[Comment]
--  执行摸牌
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.do_real_mopai(gameobj)
	local tableobj = gameobj.tableobj
	local noticemsg = nil
	local seat = nil
	local index = 0

	--设置摸牌玩家位置
	tableobj.chu_mo_paitag = EMJActionType.MJ_ACTION_TYPE_MOPAI    --摸牌
	tableobj.chu_mo_pai_card = 0   --出摸牌的牌值
	for i=1, tableobj.conf.max_player_num do
		index = (tableobj.curr_action_seat_index + i) % tableobj.conf.max_player_num
		if index == 0 then
			index = tableobj.conf.max_player_num
		end
		if not tableobj.seats[index].is_hupai and not tableobj.seats[index].is_giveup then
			break
		end 
	end
	tableobj.chu_mo_pai_seat_index = index

    --服务器摸牌
    seat = tableobj.seats[index]
    tableobj.chu_mo_pai_card = cardtool.touch_card(tableobj.cards_stack,seat.rid)
	seat.curr_mo_paicard = tableobj.chu_mo_pai_card
	cardtool.insert_card(seat.cards, tableobj.chu_mo_pai_card)

    --保存操作到游戏记录
    if not tableobj.game_records.all_player_action_list then
        tableobj.game_records.all_player_action_list = { }
    end
    local action_list = tableobj.game_records.all_player_action_list 
    local action_time = timetool.get_time()
    local action_type = EMJActionType.MJ_ACTION_TYPE_MOPAI
    local item = tostring(action_time) .. "_" .. seat.rid .. "_" .. action_type .. "_" .. tableobj.chu_mo_pai_card
    table.insert(action_list,item)
    tablelogic.save_playback_record(item)
	
    --通知当前玩家摸牌
	noticemsg = {
		rid = seat.rid,
		seat_index = seat.index,
		wait_action_type = EMJActionType.MJ_ACTION_TYPE_MOPAI,
        card = tableobj.chu_mo_pai_card,
        remain_card_num = tableobj.cards_stack.cur_num,
	}
	tablelogic.sendmsg_to_tableplayer(seat.rid, "doactionN", noticemsg)
	
	--通知其他玩家，某玩家摸牌
	noticemsg.card = nil
	tablelogic.sendmsg_to_otheralltableplayer(tableobj,seat.rid, "doactionN", noticemsg)

	--记录麻将中当前操作玩家座位，方便计算下一位
	tableobj.curr_action_seat_index = seat.index

	--摸牌结束处理
	GameLogic.clear_action_state(gameobj)

	--清除上一次杠牌信息
	if seat.index ~= tableobj.curr_gangpai_seat_index then
		GameLogic.clear_gangpai_state(gameobj)
	end

	tableobj.state = EMJTableState.TABLE_STATE_WAIT_MJ_MOPAI
	local timer_id = timer.settimer(3, "action_type_mopai")
	if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_MJ_MOPAI then
		timer.cleartimer(timer_id)
	else
		tableobj.timer_id = timer_id
	end		 
end

--[Comment]
--  处理客户端摸牌
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.action_type_mopai(gameobj)
	local tableobj = gameobj.tableobj
	local seat = tableobj.seats[tableobj.chu_mo_pai_seat_index]
	local noticemsg = nil
	local gang_cards = nil
	local player_action = nil

    tableobj.action_timeout_time = timetool.get_time() + (tableobj.conf.action_timeout or 20)

	--获得杠碰牌	
	local di_card_values = {}
	for _, v in pairs(seat.di_cards) do
		table.insert(di_card_values, v.card)
        table.insert(di_card_values, v.card)
        table.insert(di_card_values, v.card)
        if v.gang_peng_type ~= EMJGangPengType.GANGPENG_TYPE_PENG then
            table.insert(di_card_values, v.card)
        end
	end

	noticemsg = {
		rid = seat.rid,
		seat_index = seat.index,
		action_timeout_time = tableobj.action_timeout_time,
		wait_action_types = {},
        remain_card_num = tableobj.cards_stack.cur_num,
	}

    --获得杠碰牌	
	local di_card_values = {}
	for _, v in pairs(seat.di_cards) do
		table.insert(di_card_values, v.card)
        table.insert(di_card_values, v.card)
        table.insert(di_card_values, v.card)
        if v.gang_peng_type ~= EMJGangPengType.GANGPENG_TYPE_PENG then
            table.insert(di_card_values, v.card)
        end
	end

    --判断玩家是否可以胡牌
    local round_num = GameLogic.get_round_num(gameobj)
    local is_can_hu,fan_types = cardtool.check_hu(seat.cards,di_card_values,nil,seat.is_banker,round_num ,seat.que_cardcolor,tableobj.is_7zhang)
    local cards = seat.cards
    if is_can_hu then --todo
        seat.fan_types = fan_types
        table.insert(noticemsg.wait_action_types, EMJActionType.MJ_ACTION_TYPE_HUPAI)
		--判断是否为正确地胡，地胡要求没有人碰杠吃过
        if seat.fan_types[EMJHuPaiType.HUPAI_TYPE_DIHU] ~= nil then
            for _,tmp_seat in pairs(tableobj.seats) do
                if #(tmp_seat.di_cards) > 0 then
                    seat.fan_types[EMJHuPaiType.HUPAI_TYPE_DIHU] = nil
                    break
                end
            end 
        end
    end

	--摸最后一张牌后玩家不能杠
	if tableobj.cards_stack.cur_num > 0 then
		--判断是否可以暗杠
		gang_cards = cardtool.get_gang_cards(cards,seat.que_cardcolor)
		if #gang_cards > 0 then
	        table.insert(noticemsg.wait_action_types, EMJActionType.MJ_ACTION_TYPE_ANGANG)	
		end

        --判断是否可以添杠
        for _,v in pairs(cards) do
            if seat.que_cardcolor ~= math.floor(v/10) 
            and cardtool.check_peng_gang(cards,di_card_values, v, true) == 3 then
			    table.insert(noticemsg.wait_action_types, EMJActionType.MJ_ACTION_TYPE_BAGANG)
                break
            end
        end
	end

    if tableobj.action_player_list == nil then
		tableobj.action_player_list = {}
	end

    tableobj.curr_actionplayer_rid = seat.rid
	if noticemsg.wait_action_types ~= nil and #(noticemsg.wait_action_types) > 0 then
		table.insert(noticemsg.wait_action_types, EMJActionType.MJ_ACTION_TYPE_GUO)
		player_action = { }
        player_action.rid = noticemsg.rid
        player_action.seat_index = noticemsg.seat_index
        player_action.wait_action_types = tabletool.deepcopy(noticemsg.wait_action_types)
		player_action.action_state = EMJActionState.NODO
		player_action.action_type = EMJActionType.MJ_ACTION_TYPE_SELECT
		tableobj.action_player_list[seat.rid] = player_action
		
        tableobj.state = EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION
        if is_can_hu and tableobj.cards_stack.cur_num < 4 then
            local timermsg = {rid=seat.rid, index=seat.index}	
			local timerid = timer.settimer(100, "tuoguan_doaction", timermsg)
            if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION then
                timer.cleartimer(timerid)
            else
			    seat.tuoguan_doaction_timerid = timerid
            end
		elseif seat.is_tuoguan then
			local timermsg = {rid=seat.rid, index=seat.index}
            local tuoguan_time = tableobj.do_tuoguan_time * 100 + base.get_random(1,35) * 3		
			local timerid = timer.settimer(tuoguan_time, "tuoguan_doaction", timermsg)
            if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION then
                timer.cleartimer(timerid)
            else
			    seat.tuoguan_doaction_timerid = timerid
            end
		end

        if is_can_hu and tableobj.cards_stack.cur_num < 4 then

        else   
            --倒计时等待
		    tablelogic.sendmsg_to_tableplayer(seat.rid, "todoN", { todo_list = {noticemsg}})
        end

	    local timer_id = timer.settimer(tableobj.do_select_timeout * 100, "do_select")	
		tableobj.timer_id = timer_id
	else    --不能杠碰胡，出牌
        --出摸牌的表示
		if tableobj.curr_gangpai_seat_index == seat.index then
			tableobj.chu_mo_paitag = EMJActionType.MJ_ACTION_TYPE_GANG_CHUPAI     		
		else
			tableobj.chu_mo_paitag = EMJActionType.MJ_ACTION_TYPE_CHUPAI			
		end

		noticemsg.card = tableobj.chu_mo_pai_card			
		tableobj.chu_mo_pai_seat_index = seat.index

		table.insert(noticemsg.wait_action_types, EMJActionType.MJ_ACTION_TYPE_CHUPAI)
		player_action = { }
        player_action.rid = noticemsg.rid
        player_action.seat_index = noticemsg.seat_index
        player_action.wait_action_types = tabletool.deepcopy(noticemsg.wait_action_types)
		player_action.action_state = EMJActionState.NODO
		player_action.action_type = EMJActionType.MJ_ACTION_TYPE_CHUPAI		
		tableobj.action_player_list[seat.rid] = player_action
        tableobj.state = EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION
		if seat.is_tuoguan then
			local timermsg = {rid=seat.rid, index=seat.index}	
            local tuoguan_time = tableobj.do_tuoguan_time * 100 + base.get_random(1,35) * 3
			local timerid = timer.settimer(tuoguan_time, "tuoguan_doaction", timermsg)   --超时托管
			seat.tuoguan_doaction_timerid = timerid
		end
		tablelogic.sendmsg_to_tableplayer(seat.rid,"todoN", { todo_list = {noticemsg}})
        tableobj.timer_id = timer.settimer((tableobj.conf.action_timeout or 20) * 100, "doaction")
	end

    --通知其他玩家，等待某玩家出牌
	noticemsg = {
		rid = seat.rid,
		seat_index = seat.index,
		action_timeout_time = tableobj.action_timeout_time,
		wait_action_type = player_action.action_type,
		remain_card_num = tableobj.cards_stack.cur_num,
	}
	tablelogic.sendmsg_to_otheralltableplayer(tableobj,seat.rid,"todoN", { todo_list = {noticemsg}})
    tableobj.state = EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION	
end

---------------------------
--出牌

--[Comment]
--  处理客户端出牌操作
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.on_action_type_chupai(gameobj, seat, player_action)
	local tableobj = gameobj.tableobj
    local tmp_card = tableobj.chu_mo_pai_card

    if not tmp_card or tmp_card == 0 then
        tmp_card = seat.curr_mo_paicard or 0
        if tmp_card == 0 then
            tmp_card = seat.cards[#(seat.cards)]
        end
    end
    seat.curr_mo_paicard = 0

	--删除出的牌
	local status = cardtool.delete_card(seat.cards, tmp_card,seat.rid)
    if not status then
        local str_cards = ""
        for k,v in pairs(seat.cards) do
            str_cards = str_cards .. v .. "  "
        end
        filelog.sys_error("rid: " .. seat.rid,"cards:", str_cards,"action_type: chupai","card:", tmp_card)
    end

	--通知操作结果
	local noticemsg = {
		rid = seat.rid,
		seat_index = seat.index,
		wait_action_type = player_action.action_type,
		card = tableobj.chu_mo_pai_card,
        remain_card_num = tableobj.cards_stack.cur_num,
	}
	tablelogic.sendmsg_to_alltableplayer(tableobj,"doactionN", noticemsg)

	--清除当前操作状态
	GameLogic.clear_action_state(gameobj)
	tableobj.state = EMJTableState.TABLE_STATE_MJ_CHUPAI
end

--[Comment]
--  处理出牌之后的操作
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.action_type_chupai(gameobj)
	local tableobj = gameobj.tableobj
	local seat = tableobj.seats[tableobj.chu_mo_pai_seat_index]
    local noticemsgs = { }
	local player_action = nil
    
	--记录当前的出牌次数
	tableobj.chupai_count = tableobj.chupai_count + 1

	--计算下一次操作倒计时
	tableobj.action_timeout_time = timetool.get_time() + (tableobj.do_select_timeout or 20)

    GameLogic.clear_guohu_state(gameobj,seat.index)

	--判断是否有玩家可以杠碰胡
	local is_find = false
	for _, tmpseat in pairs(tableobj.seats) do
		if tmpseat.rid ~= seat.rid and not tmpseat.is_hupai and not tmpseat.is_giveup then
            local noticemsg = {
                rid = tmpseat.rid,
                seat_index = tmpseat.index,
		        action_timeout_time = tableobj.action_timeout_time,
                card = tableobj.chu_mo_pai_card,
		        wait_action_types = {},
                remain_card_num = tableobj.cards_stack.cur_num,
                chupai_seat_index = tableobj.chu_mo_pai_seat_index,

                --cards = tmpseat.cards,
                --di_cards = tmpseat.di_cards,
                --count = tableobj.chupai_count,
            }
         
			--获得碰杠牌
			local di_card_values = {}
			local cards = tmpseat.cards
			for _, v in pairs(tmpseat.di_cards) do
				table.insert(di_card_values, v.card)
                table.insert(di_card_values, v.card)
                table.insert(di_card_values, v.card)
                if v.gang_peng_type ~= EMJGangPengType.GANGPENG_TYPE_PENG then
                    table.insert(di_card_values, v.card)
                end
			end

            --判断是否可以胡牌
            local tmpcard = tableobj.chu_mo_pai_card
            local round_num = GameLogic.get_round_num(gameobj)
            local is_can_hu,fan_types = cardtool.check_hu(tmpseat.cards,di_card_values,tmpcard,tmpseat.is_banker,round_num ,tmpseat.que_cardcolor,tableobj.is_7zhang)
            if is_can_hu then  
                table.insert(noticemsg.wait_action_types, EMJActionType.MJ_ACTION_TYPE_HUPAI)
                tmpseat.fan_types = fan_types

                --去掉过胡牌
                if GameLogic.check_is_guohu_card(tmpseat,tableobj.chu_mo_pai_card) then
                    is_can_hu = false
                    tmpseat.fan_types = {}
                    table.remove(noticemsg.wait_action_types)
                    local response = {
                        rid = tmpseat.rid,
                        seat_index = tmpseat.index,
                        wait_action_type = EMJActionType.MJ_ACTION_TYPE_GUOHU,
                    }
                    tablelogic.sendmsg_to_tableplayer(tmpseat.rid,"doactionN",response)
                end
            end

			--判断是否可以碰
			if  cardtool.check_peng(tmpseat.cards, tableobj.chu_mo_pai_card,tmpseat.que_cardcolor) then
				table.insert(noticemsg.wait_action_types, EMJActionType.MJ_ACTION_TYPE_PENG)
			end

			--判断是否可以杠
            if tmpseat.que_cardcolor ~= math.floor(tmpcard/10) then
			    if tableobj.cards_stack.cur_num > 0 and cardtool.check_gang(tmpseat.cards,di_card_values,tmpcard) then
				    table.insert(noticemsg.wait_action_types, EMJActionType.MJ_ACTION_TYPE_ZHIGANG)
			    end
            end

			if #(noticemsg.wait_action_types) > 0 then
				table.insert(noticemsg.wait_action_types, EMJActionType.MJ_ACTION_TYPE_GUO)
				if tableobj.action_player_list == nil then
					tableobj.action_player_list = {}
				end
				
				player_action = { }
                player_action.rid = noticemsg.rid
                player_action.seat_index = noticemsg.seat_index
                player_action.wait_action_types = tabletool.deepcopy(noticemsg.wait_action_types)
				player_action.action_state = EMJActionState.NODO
				player_action.action_type = EMJActionType.MJ_ACTION_TYPE_SELECT
				tableobj.action_player_list[tmpseat.rid] = player_action

                table.insert(noticemsgs,noticemsg)
                tableobj.curr_actionplayer_rid = noticemsg.rid
                if is_can_hu and tableobj.cards_stack.cur_num < 4 then
                    local timermsg = {rid=tmpseat.rid, index=tmpseat.index}	
			        local timerid = timer.settimer(100, "tuoguan_doaction", timermsg)   --超时托管
				    tmpseat.tuoguan_doaction_timerid = timerid
                    table.remove(noticemsgs)
                elseif tmpseat.is_tuoguan then
			        local timermsg = {rid=tmpseat.rid, index=tmpseat.index}	
                    local tuoguan_time = tableobj.do_tuoguan_time * 100 + base.get_random(1,35) * 3
			        local timerid = timer.settimer(tuoguan_time, "tuoguan_doaction", timermsg)   --超时托管
				    tmpseat.tuoguan_doaction_timerid = timerid
		        end

				is_find = true
			end
		end
	end

	if is_find then
		tableobj.state = EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION
        if #noticemsgs > 0 then
            for _,seat in pairs(tableobj.seats) do
                local msgs = tabletool.deepcopy(noticemsgs)
                for i,msg in pairs(msgs) do
                    if msg.rid ~= seat.rid then
                        msg.wait_action_types = nil
                        msg.wait_action_type = EMJActionType.MJ_ACTION_TYPE_SELECT
                    end
                end
                tablelogic.sendmsg_to_tableplayer(seat.rid,"todoN",{ todo_list = msgs})
            end
        end
       
        --倒计时等待
	    local timer_id = timer.settimer(tableobj.do_select_timeout * 100, "do_select")	
	    if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION then
		    timer.cleartimer(timer_id)
	    else
		    tableobj.timer_id = timer_id
	    end
		return		
	end

    --插入已出牌列表
	cardtool.insert_card(seat.out_cards, tableobj.chu_mo_pai_card)

    --判断是否牌已摸完
	if tableobj.cards_stack.cur_num == 0 then	 
		GameLogic.clear_action_state(gameobj)
		--流局处理
        tableobj.state = EMJTableState.TABLE_STATE_ONE_GAME_END
        tableobj.is_liuju = true
	else		
		tableobj.state = EMJTableState.TABLE_STATE_MJ_DO_MOPAI
	end
end

---------------------------
--过牌

--[Comment]
--  处理客户端过牌操作
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.on_action_type_guopai(gameobj,cur_seat, player_action)
	local tableobj = gameobj.tableobj
	local noticemsg = nil
	local seat = tableobj.seats[tableobj.chu_mo_pai_seat_index]
	local tmpseat = nil
	local tmpplayer_action = nil

    --清空计时器
    if tableobj.timer_id ~= -1 then
        timer.cleartimer(tableobj.timer_id)
        tableobj.timer_id = -1
    end

    --计算下一次操作倒计时
	tableobj.action_timeout_time = timetool.get_time() + (tableobj.conf.action_timeout or 20)

	--摸牌玩家不做任何处理，则通知玩家出牌
	if tableobj.chu_mo_paitag == EMJActionType.MJ_ACTION_TYPE_MOPAI then 
        --tableobj.action_timeout_time = timetool.get_time() + 10

		--清除之前的状态
		GameLogic.clear_action_state(gameobj)

        --通知其他玩家，某玩家出牌
        seat = tableobj.seats[tableobj.chu_mo_pai_seat_index]
		seat.fan_types = {}
		noticemsg = {
			rid = seat.rid,
			seat_index = seat.index,
			action_timeout_time = tableobj.action_timeout_time,
			wait_action_type = EMJActionType.MJ_ACTION_TYPE_CHUPAI,
            remain_card_num = tableobj.cards_stack.cur_num,
		}
        tablelogic.sendmsg_to_otheralltableplayer(tableobj,seat.rid,"todoN", { todo_list = {noticemsg}})

        --通知摸牌玩家出牌
		noticemsg = {
			rid = seat.rid,
			seat_index = seat.index,
			action_timeout_time = tableobj.action_timeout_time,
			wait_action_types = {EMJActionType.MJ_ACTION_TYPE_CHUPAI},
            remain_card_num = tableobj.cards_stack.cur_num,

            --cards = seat.cards,
            --di_cards = seat.di_cards,
            --count = tableobj.chupai_count,
		}
        
		tableobj.chu_mo_paitag = EMJActionType.MJ_ACTION_TYPE_CHUPAI
		tableobj.chu_mo_pai_seat_index = seat.index		
		tableobj.chu_mo_pai_card = 0

		if tableobj.action_player_list == nil then
			tableobj.action_player_list = {}
		end
		
        tmpplayer_action = { }
        tmpplayer_action.rid = noticemsg.rid
        tmpplayer_action.seat_index = noticemsg.seat_index
        tmpplayer_action.wait_action_types = tabletool.deepcopy(noticemsg.wait_action_types)
		tmpplayer_action.action_state = EMJActionState.NODO
		tmpplayer_action.action_type = EMJActionType.MJ_ACTION_TYPE_CHUPAI
		tableobj.action_player_list[seat.rid] = tmpplayer_action		
		tableobj.state = EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION

		if seat.is_tuoguan then
			local timermsg = {rid=seat.rid, index=seat.index}
            local out_time = tableobj.do_tuoguan_time * 100 + base.get_random(1,35) * 3
			local timerid = timer.settimer(out_time, "tuoguan_doaction", timermsg)
			if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION 
				or tableobj.action_player_list[timermsg.rid] == nil then
				timer.cleartimer(timerid)
			else
				seat.tuoguan_doaction_timerid = timerid
			end
		end
		tablelogic.sendmsg_to_tableplayer(seat.rid,"todoN", { todo_list = {noticemsg}})	
        local out_time = (tableobj.conf.action_timeout or 20)
        local timer_id = timer.settimer(out_time * 100, "doaction")	
	    if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION then
		    timer.cleartimer(timer_id)
	    else
		    tableobj.timer_id = timer_id
	    end
		return 
	end

    --通知其他玩家，某玩家选择过牌
    local response = {
			rid = player_action.rid,
			seat_index = player_action.seat_index,
			wait_action_type = EMJActionType.MJ_ACTION_TYPE_GUO,
            remain_card_num = tableobj.cards_stack.cur_num,
	}
    tablelogic.sendmsg_to_alltableplayer(tableobj,"doactionN", response)

    -------------------
     --之前操作玩家是添杠，则继续处理（被抢杠胡打断了）
	if tableobj.chu_mo_paitag == EMJActionType.MJ_ACTION_TYPE_BAGANG then
		seat = tableobj.seats[tableobj.chu_mo_pai_seat_index]
		noticemsg = {
			rid = seat.rid,
			seat_index = seat.index,
			wait_action_type = EMJActionType.MJ_ACTION_TYPE_BAGANG,
			card = tableobj.chu_mo_pai_card,
            remain_card_num = tableobj.cards_stack.cur_num,
		}

         --杠牌结算
        local win_seat_indexs = GameLogic.settle_gang_pai(gameobj,seat.index,seat.index,EMJGangPengType.GANGPENG_TYPE_BAGANG)

        --保存杠牌信息
        local gangpengitem = { }
		for _, v in pairs(seat.di_cards) do
			if v.card == tableobj.chu_mo_pai_card then
				gangpengitem.card = v.card
				gangpengitem.gang_peng_type = EMJGangPengType.GANGPENG_TYPE_BAGANG
				gangpengitem.gang_seat_index = tableobj.chu_mo_pai_seat_index
                v.gang_peng_type = EMJGangPengType.GANGPENG_TYPE_BAGANG
                v.gang_seat_index = tableobj.chu_mo_pai_seat_index
                v.win_seat_indexs = win_seat_indexs
				break
			end
		end

        gangpengitem.win_seat_indexs = win_seat_indexs
        noticemsg.gang_peng_info = tabletool.deepcopy(gangpengitem)
		--tablelogic.sendmsg_to_alltableplayer(tableobj,"doactionN", noticemsg)

		tableobj.curr_gangpai_seat_index = seat.index                       --记录当前杠牌座位号
		tableobj.curr_gangpai_info = tabletool.deepcopy(gangpengitem)       --记录当前杠牌信息

		--清除玩家操作状态
		GameLogic.clear_action_state(gameobj)

        tableobj.curr_action_seat_index = seat.index - 1
		if tableobj.curr_action_seat_index == 0 then
			tableobj.curr_action_seat_index = tableobj.conf.max_player_num
		end

        --检测是否有玩家输光
        if GameLogic.check_is_loseall(tableobj) then
            return
        end

		tableobj.state = EMJTableState.TABLE_STATE_WAIT_MJ_DO_MOPAI
		local timer_id = timer.settimer(5, "do_mopai")
		if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_MJ_DO_MOPAI then
			timer.cleartimer(timer_id)
		else
			tableobj.timer_id = timer_id
		end
		return
	end

    --继续下个玩家摸牌

	--判断游戏是否结束,流局
	if tableobj.cards_stack.cur_num == 0 then
		--清除玩家操作状态
		GameLogic.clear_action_state(gameobj)
		tableobj.state = EMJTableState.TABLE_STATE_ONE_GAME_END
        tableobj.is_liuju = true
		return
	end

	seat = tableobj.seats[tableobj.chu_mo_pai_seat_index]
	cardtool.insert_card(seat.out_cards, tableobj.chu_mo_pai_card)

	--清除之前的状态
	GameLogic.clear_action_state(gameobj)
	if seat.index ~= tableobj.curr_gangpai_seat_index then
		GameLogic.clear_gangpai_state(gameobj)
	end

	--记录当前的操作座位号
	tableobj.curr_action_seat_index = seat.index
	tableobj.state = EMJTableState.TABLE_STATE_WAIT_MJ_DO_MOPAI
	local timer_id = timer.settimer(5, "do_mopai")
	if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_MJ_DO_MOPAI then
		timer.cleartimer(timer_id)
	else
		tableobj.timer_id = timer_id
	end
end

---------------------------
--碰牌

--[Comment]
--  处理客户端碰牌操作
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.on_action_type_pengpai(gameobj,seat, player_action)
	local tableobj = gameobj.tableobj
	local noticemsg = nil
	local chupai_seat = nil
	local peng_seat = nil
	local tmpplayer_action = nil

	--处理碰牌
	if player_action.action_type == EMJActionType.MJ_ACTION_TYPE_PENG then
		peng_seat = tableobj.seats[player_action.seat_index]

		noticemsg = {
			rid = peng_seat.rid,
			seat_index = peng_seat.index,
			wait_action_type = player_action.action_type,
			card = tableobj.chu_mo_pai_card,
            remain_card_num = tableobj.cards_stack.cur_num,
		}
        local gangpengitem = {
				gang_seat_index =tableobj.chu_mo_pai_seat_index,
				gang_peng_type = EMJGangPengType.GANGPENG_TYPE_PENG,
				card = tableobj.chu_mo_pai_card,
		}
        noticemsg.gang_peng_info = tabletool.deepcopy(gangpengitem)

        --通知所有玩家，某玩家碰牌
		tablelogic.sendmsg_to_alltableplayer(tableobj,"doactionN",noticemsg)

		--清除玩家手上的碰牌
        local tmp_card = tableobj.chu_mo_pai_card
		local status = cardtool.delete_cards(peng_seat.cards, {tmp_card, tmp_card},peng_seat.rid)
        if not status then
            local str_cards = ""
            for k,v in pairs(peng_seat.cards) do
                str_cards = str_cards .. v .. "  "
            end
            filelog.sys_error("rid: " .. peng_seat.rid,"cards:", str_cards,"action_type: pengpai","card:", tmp_card)
        end
		table.insert(peng_seat.di_cards, gangpengitem)					
	end

	--清除之前的状态
	GameLogic.clear_action_state(gameobj)

	--清除之前的杠牌状态
	GameLogic.clear_gangpai_state(gameobj)

    --清除过手胡
    GameLogic.clear_guohu_state(gameobj,peng_seat.index)

	if peng_seat == nil then
		filelog.sys_error("GameLogic.on_action_type_pengpai peng_seat == nil", tableobj)
		return
	end

	peng_seat.curr_mo_paicard = 0

	--通知碰牌玩家出牌
	tableobj.curr_action_seat_index = peng_seat.index
	tableobj.action_timeout_time = timetool.get_time() + (tableobj.conf.action_timeout	or 20)	
	noticemsg = {
		rid = peng_seat.rid,
		seat_index = peng_seat.index,
		action_timeout_time = tableobj.action_timeout_time,
		wait_action_types = {
			EMJActionType.MJ_ACTION_TYPE_CHUPAI,	
		},
        remain_card_num = tableobj.cards_stack.cur_num,

        --cards = peng_seat.cards,
        --di_cards = peng_seat.di_cards,
        --count = tableobj.chupai_count,
	}

	--记录出牌位置
	tableobj.chu_mo_pai_seat_index = peng_seat.index
	tableobj.chu_mo_paitag = EMJActionType.MJ_ACTION_TYPE_CHUPAI
	tableobj.chu_mo_pai_card = 0

	if tableobj.action_player_list == nil then
		tableobj.action_player_list = {}
	end

	tmpplayer_action = { }
    tmpplayer_action.rid = noticemsg.rid
    tmpplayer_action.seat_index = noticemsg.seat_index
    tmpplayer_action.wait_action_types = tabletool.deepcopy(noticemsg.wait_action_types)
	tmpplayer_action.action_state = EMJActionState.NODO
	tmpplayer_action.action_type = EMJActionType.MJ_ACTION_TYPE_CHUPAI
	tableobj.action_player_list[peng_seat.rid] = tmpplayer_action	
    			
	tableobj.state = EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION
	if peng_seat.is_tuoguan then
		local timermsg = {rid=peng_seat.rid, index=peng_seat.index}	
        local out_time = tableobj.do_tuoguan_time * 100 + base.get_random(1,35) * 3
		local timerid = timer.settimer(out_time, "tuoguan_doaction", timermsg)
		if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION 
			or tableobj.action_player_list[timermsg.rid] == nil then
			timer.cleartimer(timerid)
		else
			peng_seat.tuoguan_doaction_timerid = timerid
		end
	end
	tablelogic.sendmsg_to_tableplayer(peng_seat.rid,"todoN", { todo_list = {noticemsg}})	
    local out_time = tableobj.conf.action_timeout or 20
    local timer_id = timer.settimer(out_time * 100, "doaction")	
	if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION then
		timer.cleartimer(timer_id)
	else
		tableobj.timer_id = timer_id
	end			

    --通知其他玩家，碰牌玩家出牌
    noticemsg.wait_action_types = nil
	noticemsg.wait_action_type = EMJActionType.MJ_ACTION_TYPE_CHUPAI
	tablelogic.sendmsg_to_otheralltableplayer(tableobj,peng_seat.rid,"todoN", { todo_list = {noticemsg}})
end

---------------------------
--暗杠

--[Comment]
-- 处理客户端暗杠操作
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.on_action_type_angang(gameobj,seat, player_action)
	local tableobj = gameobj.tableobj
	local noticemsg = nil
	local chupai_seat = nil
	local card = tableobj.curr_actionplayer_cards[1]

	seat = tableobj.seats[player_action.seat_index]
	seat.curr_mo_paicard = 0
	seat.is_gang = true

	--通知玩家杠碰结果
	noticemsg = {
		rid = seat.rid,
		seat_index = seat.index,
		wait_action_type = player_action.action_type,
		card = card,  --暗杠其他玩家不广播杠什么牌
        remain_card_num = tableobj.cards_stack.cur_num,
	}

     --杠牌结算
    local win_seat_indexs = GameLogic.settle_gang_pai(gameobj,seat.index,seat.index,EMJGangPengType.GANGPENG_TYPE_ANGANG)

    local gangpengitem = {
			gang_seat_index = tableobj.chu_mo_pai_seat_index,
			gang_peng_type = EMJGangPengType.GANGPENG_TYPE_ANGANG,  --杠碰类型 1 碰,2 直杠,3 巴杠（面下杠）4 暗杠	
			card = card,
            win_seat_indexs = win_seat_indexs,
	}

    noticemsg.gang_peng_info = tabletool.deepcopy(gangpengitem)
	tablelogic.sendmsg_to_otheralltableplayer(tableobj,seat.rid,"doactionN", noticemsg)	

    --给自己发通知，自己可以看到牌
     gangpengitem.card = card
     noticemsg.gang_peng_info.card = card
     noticemsg.card = card
    tablelogic.sendmsg_to_tableplayer(seat.rid,"doactionN", noticemsg)	

   
	
	tableobj.curr_action_seat_index = seat.index - 1
	if tableobj.curr_action_seat_index == 0 then
		tableobj.curr_action_seat_index = tableobj.conf.max_player_num
	end

	--清除玩家手上的杠牌
	local status = cardtool.delete_cards(seat.cards, {card,card,card,card},seat.rid)		
    if not status then
        local str_cards = ""
        for k,v in pairs(seat.cards) do
            str_cards = str_cards .. v .. "  "
        end
        filelog.sys_error("rid: " .. seat.rid,"cards:", str_cards,"action_type: angang","card:", card)
    end			
	table.insert(seat.di_cards, gangpengitem)					

	--摸牌结束处理
	GameLogic.clear_action_state(gameobj)

    --清除过手胡
    GameLogic.clear_guohu_state(gameobj,seat.index)

	tableobj.curr_gangpai_seat_index = seat.index                   --记录当前杠牌座位号
	tableobj.curr_gangpai_info = tabletool.deepcopy(gangpengitem)   --记录当前杠牌信息

     --检测是否有玩家输光
    if GameLogic.check_is_loseall(tableobj) then
        return
    end

	tableobj.state = EMJTableState.TABLE_STATE_WAIT_MJ_DO_MOPAI
	local timer_id = timer.settimer(5, "do_mopai")
	if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_MJ_DO_MOPAI then
		timer.cleartimer(timer_id)
	else
		tableobj.timer_id = timer_id
	end
end

---------------------------
--添杠（弯杠）

--[Comment]
-- 处理客户端添杠操作
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.on_action_type_wangang(gameobj,seat, player_action)
 	local tableobj = gameobj.tableobj
	local noticemsg = nil
	local tmpplayer_action = nil
	local tmpseat = nil
	local card = tableobj.curr_actionplayer_cards[1]

	local qiang_gang_msg = {}
	seat = tableobj.seats[player_action.seat_index]
	seat.curr_mo_paicard = 0

    tableobj.action_timeout_time = timetool.get_time() + (tableobj.conf.action_timeout or 20)

     --清除过手胡
    GameLogic.clear_guohu_state(gameobj,seat.index)

    --删除摸的牌
	local status = cardtool.delete_card(seat.cards, card,seat.rid)
    if not status then
        local str_cards = ""
        for k,v in pairs(seat.cards) do
            str_cards = str_cards .. v .. "  "
        end
        filelog.sys_error("rid: " .. seat.rid,"cards:", str_cards,"action_type: wangang","card:", card)
    end		

	--判断是否有人可以抢杠
	for _, tmpseat in pairs(tableobj.seats) do
		if tmpseat.rid ~= seat.rid and not tmpseat.is_hupai and not tmpseat.is_giveup then
			noticemsg = {
				rid = tmpseat.rid,
				seat_index = tmpseat.index,
                action_timeout_time = tableobj.action_timeout_time,
				wait_action_types = {},
                remain_card_num = tableobj.cards_stack.cur_num,
			}

			--判断是否可以胡牌
			local di_card_values = {}
			local cards = tmpseat.cards
			for _, v in pairs(tmpseat.di_cards) do
				table.insert(di_card_values, v.card)
                table.insert(di_card_values, v.card)
                table.insert(di_card_values, v.card)
                if v.gang_peng_type ~= EMJGangPengType.GANGPENG_TYPE_PENG then
                    table.insert(di_card_values, v.card)
                end
			end

			--判断是否海底炮
			if tableobj.cards_stack.cur_num == 0 then
							
			end 				

            local round_num = GameLogic.get_round_num(gameobj)
            local is_hu,fan_types = cardtool.check_hu(tmpseat.cards,di_card_values,card,tmpseat.is_banker,round_num ,tmpseat.que_cardcolor,tableobj.is_7zhang)
			if is_hu then
                table.insert(noticemsg.wait_action_types, EMJActionType.MJ_ACTION_TYPE_HUPAI)
                tmpseat.fan_types = fan_types
			end 
			
			if #(noticemsg.wait_action_types) > 0 then
				table.insert(noticemsg.wait_action_types, EMJActionType.MJ_ACTION_TYPE_GUO)
                tmpseat.is_qiang_gang = true    --抢杠加2倍
				qiang_gang_msg[tmpseat.rid] = noticemsg				
			end

            --去掉过胡玩家
            if GameLogic.check_is_guohu_card(tmpseat,card) then
                tmpseat.fan_types = {}
                tmpseat.is_qiang_gang = false
                qiang_gang_msg[tmpseat.rid] = nil	
                noticemsg = nil
                local response = {
                    rid = tmpseat.rid,
                    seat_index = tmpseat.index,
                    wait_action_type = EMJActionType.MJ_ACTION_TYPE_GUOHU,
                }
                tablelogic.sendmsg_to_tableplayer(tmpseat.rid,"doactionN",response)
            end	
		end
	end

	--没有玩家抢杠胡，摸牌结束处理
	GameLogic.clear_action_state(gameobj)
	if tabletool.is_emptytable(qiang_gang_msg) then
		seat.is_gang = true
		tableobj.curr_action_seat_index = seat.index - 1
		if tableobj.curr_action_seat_index == 0 then
			tableobj.curr_action_seat_index = tableobj.conf.max_player_num
		end

		--通知玩家杠牌结果
		noticemsg = {
			rid = seat.rid,
			seat_index = seat.index,
			wait_action_type = player_action.action_type,
			card = card,
            remain_card_num = tableobj.cards_stack.cur_num,
		}

        local gangpengitem = { }
        gangpengitem.card = card
        gangpengitem.gang_peng_type = EMJGangPengType.GANGPENG_TYPE_BAGANG
        gangpengitem.gang_seat_index = tableobj.chu_mo_pai_seat_index

        --杠牌结算
        local win_seat_indexs = GameLogic.settle_gang_pai(gameobj,seat.index,seat.index,EMJGangPengType.GANGPENG_TYPE_BAGANG)

        gangpengitem.win_seat_indexs = win_seat_indexs

        --更改碰牌为杠牌
        for _, v in pairs(seat.di_cards) do
            if v.card == card then
                v.gang_peng_type = EMJGangPengType.GANGPENG_TYPE_BAGANG
                v.gang_seat_index = seat.index
                v.win_seat_indexs = win_seat_indexs
                break
            end
        end
        
        noticemsg.gang_peng_info = tabletool.deepcopy(gangpengitem)
		tablelogic.sendmsg_to_alltableplayer(tableobj,"doactionN", noticemsg)	

		tableobj.curr_gangpai_seat_index = seat.index                       --记录当前杠牌座位号
		tableobj.curr_gangpai_info = tabletool.deepcopy(gangpengitem)       --记录当前杠牌信息

        --检测是否有玩家输光
        if GameLogic.check_is_loseall(tableobj) then
            return
        end

		tableobj.state = EMJTableState.TABLE_STATE_WAIT_MJ_DO_MOPAI
		local timer_id = timer.settimer(5, "do_mopai")
		if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_MJ_DO_MOPAI then
			timer.cleartimer(timer_id)
		else
			tableobj.timer_id = timer_id
		end
	else    --有抢杠胡

		--先通知所有玩家某人添杠
		tableobj.chu_mo_pai_seat_index = seat.index
		tableobj.chu_mo_pai_card = card
		tableobj.chu_mo_paitag = EMJActionType.MJ_ACTION_TYPE_BAGANG

		noticemsg = {
			rid = seat.rid,
			seat_index = seat.index,
			wait_action_type = EMJActionType.MJ_ACTION_TYPE_BAGANG,
			card = card,
            remain_card_num = tableobj.cards_stack.cur_num,
		}
		tablelogic.sendmsg_to_alltableplayer(tableobj,"doactionN", noticemsg)	
        	
		--再通知能抢杠玩家胡牌
		if tableobj.action_player_list == nil then
			tableobj.action_player_list = {}
		end

		tableobj.state = EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION
       
        local noticemsgs = { }
	    for rid, msg in pairs(qiang_gang_msg) do
			tmpplayer_action = { }
            tmpplayer_action.rid = msg.rid
            tmpplayer_action.seat_index = msg.seat_index
            tmpplayer_action.wait_action_types = tabletool.deepcopy(msg.wait_action_types)
			tmpplayer_action.action_state = EMJActionState.NODO
			tmpplayer_action.action_type = EMJActionType.MJ_ACTION_TYPE_SELECT
			tableobj.action_player_list[rid] = tmpplayer_action

            table.insert(noticemsgs,msg)
            tableobj.curr_actionplayer_rid = msg.rid

            local tuoguan_seat = tableobj.seats[msg.seat_index]
            if tuoguan_seat.is_tuoguan then
		        local timermsg = {rid = tuoguan_seat.rid, index = tuoguan_seat.index}	
                local out_time = tableobj.do_tuoguan_time * 100 + base.get_random(1,35) * 3
		        local timerid = timer.settimer(out_time, "tuoguan_doaction", timermsg)
		        if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION then
			        timer.cleartimer(timerid)
		        else
			        tuoguan_seat.tuoguan_doaction_timerid = timerid
		        end
	        end
		end
         
         --通知所有可抢杠人
         for _,seat in pairs(tableobj.seats) do
            local msgs = tabletool.deepcopy(noticemsgs)
            for _,msg in pairs(msgs) do
                if msg.rid ~= seat.rid then
                    msg.wait_action_types = nil
                    msg.wait_action_type = EMJActionType.MJ_ACTION_TYPE_SELECT
                end
            end
            tablelogic.sendmsg_to_tableplayer(seat.rid,"todoN",{ todo_list = msgs})
        end

        --倒计时等待
	    local timer_id = timer.settimer(tableobj.do_select_timeout * 100, "do_select")	
	    if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_CLIENT_ACTION then
		    timer.cleartimer(timer_id)
	    else
		    tableobj.timer_id = timer_id
	    end
	end
end 

---------------------------
--明杠(普通杠)

--[Comment]
-- 处理客户端明杠操作
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.on_action_type_minggang(gameobj,seat, player_action)
 	local tableobj = gameobj.tableobj
	local noticemsg = nil
	local gang_seat = seat
    local gangpengitem = nil

	--处理杠牌玩家
	if player_action.action_type == EMJActionType.MJ_ACTION_TYPE_ZHIGANG then
		gang_seat.is_gang = true

        --通知所有玩家，某人杠牌
		noticemsg = {
			rid = gang_seat.rid,
			seat_index = gang_seat.index,
			wait_action_type = player_action.action_type,
			card = tableobj.chu_mo_pai_card,
            remain_card_num = tableobj.cards_stack.cur_num,
		}

        gangpengitem = {
				gang_seat_index = tableobj.chu_mo_pai_seat_index,
				gang_peng_type = EMJGangPengType.GANGPENG_TYPE_ZHIGANG,	
				card = tableobj.chu_mo_pai_card,
		}

        --杠牌结算
        local win_seat_indexs = GameLogic.settle_gang_pai(gameobj,gang_seat.index,tableobj.chu_mo_pai_seat_index,EMJGangPengType.GANGPENG_TYPE_ZHIGANG)

        gangpengitem.win_seat_indexs = win_seat_indexs
        noticemsg.gang_peng_info = tabletool.deepcopy(gangpengitem)
		tablelogic.sendmsg_to_alltableplayer(tableobj,"doactionN", noticemsg)

					
		--清除玩家手上的杠牌
        local tmp_card = tableobj.chu_mo_pai_card
		local status = cardtool.delete_cards(gang_seat.cards, {tmp_card,tmp_card,tmp_card},gang_seat.rid)
        if not status then
            local str_cards = ""
            for k,v in pairs(gang_seat.cards) do
                str_cards = str_cards .. v .. "  "
            end
            filelog.sys_error("rid: " .. gang_seat.rid,"cards:", str_cards,"action_type: minggang","card:", tmp_card)
        end	
		table.insert(gang_seat.di_cards, gangpengitem)
	end

	tableobj.curr_action_seat_index = gang_seat.index - 1
	if tableobj.curr_action_seat_index == 0 then
		tableobj.curr_action_seat_index = tableobj.conf.max_player_num
	end

	--摸牌结束处理
	GameLogic.clear_action_state(gameobj)
	gang_seat.curr_mo_paicard = 0

    --清除过手胡
    GameLogic.clear_guohu_state(gameobj,gang_seat.index)

	tableobj.curr_gangpai_seat_index = gang_seat.index              --记录当前杠牌座位号
	tableobj.curr_gangpai_info = tabletool.deepcopy(gangpengitem)   --记录当前杠牌信息

    --检测是否有玩家输光
    if GameLogic.check_is_loseall(tableobj) then
        return
    end

	tableobj.state = EMJTableState.TABLE_STATE_WAIT_MJ_DO_MOPAI
	local timer_id = timer.settimer(5, "do_mopai")
	if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_MJ_DO_MOPAI then
		timer.cleartimer(timer_id)
	else
		tableobj.timer_id = timer_id
	end
end

---------------------------
--胡牌

function GameLogic.get_max_hupai_type(fan_types)
    --获得最大胡牌类型
    local max_type = fan_types.max_type
    local is_zimo = false

    if max_type == EMJHuPaiType.HUPAI_TYPE_PINGHU then
        for fan_type,val in pairs(fan_types) do
            if type(val) == "boolean" then
                if fan_type == EMJHuPaiType.HUPAI_TYPE_ZIMO then
                    is_zimo = true
                else
                    max_type = fan_type
                    break
                end
            end
        end
    end

    if max_type == EMJHuPaiType.HUPAI_TYPE_PINGHU and is_zimo then
        max_type = EMJHuPaiType.HUPAI_TYPE_ZIMO
    end

   return max_type
end

--[Comment]
-- 处理客户端胡牌操作
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.on_action_type_hupai(gameobj,cur_seat, player_action)
	local tableobj = gameobj.tableobj
	local hupai_player_num = 0  --记录胡牌玩家数
	local noticemsg = nil
	local seat = tableobj.seats[tableobj.chu_mo_pai_seat_index]
	local tmpseat = nil

	--计算胡牌玩家数
	for _, v in pairs(tableobj.action_player_list) do
		if v.action_type == EMJActionType.MJ_ACTION_TYPE_HUPAI then
			hupai_player_num = hupai_player_num + 1
		end
	end

    --设置下局庄家位置
    if tableobj.ypdx_seat_index == 0 and  tableobj.hupai_seat_index == 0 then
        if hupai_player_num >= 2 then
		    tableobj.ypdx_seat_index = tableobj.chu_mo_pai_seat_index   --导致多家胡的玩家的位置
	    elseif hupai_player_num == 1 then
            tableobj.hupai_seat_index = player_action.seat_index 
        end
    end

	--胡牌处理
    local hu_seat_indexs = { }
    local is_find = false
	for rid, player_action in pairs(tableobj.action_player_list) do
		if player_action.action_type == EMJActionType.MJ_ACTION_TYPE_HUPAI then
			tmpseat = tableobj.seats[player_action.seat_index]
			tmpseat.hupai_card = tableobj.chu_mo_pai_card
			tmpseat.curr_mo_paicard = 0
			tmpseat.is_hupai = true

            tmpseat.yinhu_seat_index = tableobj.chu_mo_pai_seat_index

            if tableobj.chu_mo_paitag == EMJActionType.MJ_ACTION_TYPE_BAGANG then       --抢杠
				tmpseat.fan_types[EMJHuPaiType.HUPAI_TYPE_GANG_QIANG_GANG] = true
                tmpseat.yinhu_seat_index = tableobj.chu_mo_pai_seat_index
            end

            if tableobj.curr_gangpai_info ~= nil then
                if tableobj.chu_mo_paitag == EMJActionType.MJ_ACTION_TYPE_MOPAI             --杠上花
			    and tableobj.curr_gangpai_seat_index == tableobj.chu_mo_pai_seat_index then
                    tmpseat.fan_types[EMJHuPaiType.HUPAI_TYPE_GANG_SHANG_HUA] = true
                    tmpseat.yinhu_seat_index = tableobj.chu_mo_pai_seat_index
                end
   	
		        if tableobj.chu_mo_paitag == EMJActionType.MJ_ACTION_TYPE_MOPAI             --点杠花
			    and tableobj.curr_gangpai_seat_index == tableobj.chu_mo_pai_seat_index
			    and tableobj.curr_gangpai_info.gang_peng_type == EMJGangPengType.GANGPENG_TYPE_ZHIGANG then
                    tmpseat.fan_types[EMJHuPaiType.HUPAI_TYPE_DIAN_GANG_HUA] = true
                    if not tableobj.conf.is_dianganghua_as_zimo then
                        tmpseat.yinhu_seat_index = tableobj.curr_gangpai_info.gang_seat_index
                    else
                        tmpseat.yinhu_seat_index = tmpseat.index
                    end
                end
            end

            if tableobj.chu_mo_paitag == EMJActionType.MJ_ACTION_TYPE_MOPAI then    --自摸胡
                tmpseat.fan_types[EMJHuPaiType.HUPAI_TYPE_ZIMO] = true
                --判断是否海底捞,自摸最后一张牌
			    if tableobj.cards_stack.cur_num == 0 then                           --海底捞
                    tmpseat.fan_types[EMJHuPaiType.HUPAI_TYPE_HAIDILAO] = true
			    end
            end

            --如果是杠出牌,杠上炮	
			if tableobj.chu_mo_paitag == EMJActionType.MJ_ACTION_TYPE_GANG_CHUPAI then  --杠上炮
	            tmpseat.fan_types[EMJHuPaiType.HUPAI_TYPE_GANG_SHANG_PAO] = true
                tmpseat.yinhu_seat_index = tableobj.chu_mo_pai_seat_index
			end

            --判断是否海底炮,点炮最后一张牌
            if tableobj.chu_mo_paitag == EMJActionType.MJ_ACTION_TYPE_GANG_CHUPAI       --海底炮
             or  tableobj.chu_mo_paitag == EMJActionType.MJ_ACTION_TYPE_CHUPAI then
			    if tableobj.cards_stack.cur_num == 0 then
                    tmpseat.fan_types[EMJHuPaiType.HUPAI_TYPE_HAIDIPAO] = true
                    tmpseat.yinhu_seat_index = tableobj.chu_mo_pai_seat_index
			    end
            end
            
            is_find = true
            table.insert(hu_seat_indexs,tmpseat.index)
		end
	end

	GameLogic.clear_gangpai_state(gameobj)

	--通知玩家胡牌结果
    if is_find then
        
        --单次胡牌结算
        GameLogic.settle_once_hupai(gameobj,hu_seat_indexs)
        for _,i in pairs(hu_seat_indexs) do
            tableobj.seats[i].is_gameend = true
        end

        --通知所有玩家，某人胡牌
        for  rid, player_action in pairs(tableobj.action_player_list) do
	        if player_action.action_type == EMJActionType.MJ_ACTION_TYPE_HUPAI then
		        tmpseat = tableobj.seats[player_action.seat_index]
		        noticemsg = {
			        rid = tmpseat.rid,
			        seat_index = tmpseat.index,
			        wait_action_type = player_action.action_type,
			        card = tableobj.chu_mo_pai_card,
                    remain_card_num = tableobj.cards_stack.cur_num,
                    gang_peng_info = {
                        card = tmpseat.hupai_card, 
                        gang_seat_index = tmpseat.yinhu_seat_index,
                    },
		        }

                --获得最大胡牌类型
                noticemsg.hupai_type = GameLogic.get_max_hupai_type(tmpseat.fan_types)
                tmpseat.hupai_type = noticemsg.hupai_type

                --通知胡牌
		        tablelogic.sendmsg_to_alltableplayer(tableobj,"doactionN", noticemsg)		
		        tableobj.curr_action_seat_index = tmpseat.index
                if tableobj.table_type ~= EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA 
                and tableobj.is_can_half_leave == true then
                    tmpseat.is_can_half_leave = true    --可以中途离开
                end
	        end
        end
       
    end

	if GameLogic.is_onegame_canend(gameobj) then
        GameLogic.clear_action_state(gameobj)
        tableobj.state = EMJTableState.TABLE_STATE_WAIT_ONE_GAME_END
        local timer_id = timer.settimer(100, "onegameend")
	    if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_ONE_GAME_END then
		    timer.cleartimer(timer_id)
	    else
		    tableobj.timer_id = timer_id
	    end
		return
	end
    GameLogic.clear_action_state(gameobj)

    --检测是否有玩家输光
    if is_find and GameLogic.check_is_loseall(tableobj) then
       return
    end

	--未三家胡牌，继续摸牌
	tableobj.state = EMJTableState.TABLE_STATE_WAIT_MJ_DO_MOPAI
	local timer_id = timer.settimer(100, "do_mopai")
	if tableobj.state ~= EMJTableState.TABLE_STATE_WAIT_MJ_DO_MOPAI then
		timer.cleartimer(timer_id)
	else
		tableobj.timer_id = timer_id
	end
end

------------------------------------------------------------------
----其他方法

--[Comment]
--  继续执行站起操作
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.continue_and_standup(gameobj)
	GameLogic.continue(gameobj)
end

--[Comment]
--  继续执行离桌操作
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.continue_and_leave(gameobj)
	
end

--[Comment]
--  坐下
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.on_sitdown_table(gameobj, seat)
    local tableobj = gameobj.tableobj
	if tableobj.delete_table_timer_id > 0 then
		timer.cleartimer(tableobj.delete_table_timer_id)
		tableobj.delete_table_timer_id = -1
	end 
end

--[Comment]
--  等待坐下
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.wait_player_sitdown(gameobj)
	local tableobj = gameobj.tableobj
    if tableobj.sitdown_player_num <= 0 and tableobj.cur_watch_playernum <= 0 then
        if tableobj.delete_table_timer_id > 0 then
			timer.cleartimer(tableobj.delete_table_timer_id)
			tableobj.delete_table_timer_id = -1
		end
        --倒计时删除桌子
 		tableobj.delete_table_timer_id = timer.settimer(10 * 100, "delete_table")
    end
end

--[Comment]
--  发送退税，大叫，花猪消息
--
function GameLogic.send_ts_dj_hz_msgs(tableobj)
    if tableobj.wait_noticemsgs and #(tableobj.wait_noticemsgs) > 0 then
        local msga = table.remove(tableobj.wait_noticemsgs)
        local msgb = table.remove(tableobj.wait_noticemsgs)

        if msga then
            local msgname = msga.msgname
            msga.msgname = nil
            tablelogic.sendmsg_to_alltableplayer(tableobj,msgname,msga)
        end
        if msgb then
            local msgname = msgb.msgname
            msgb.msgname = nil
            tablelogic.sendmsg_to_alltableplayer(tableobj,msgname,msgb)
        end

        --倒计时等待
        tableobj.timer_id = timer.settimer(200, "wait_send_msg")
        return
    end

    tableobj.wait_noticemsgs = nil
    tableobj.timer_id = timer.settimer(5, "onegamerealend")
end

--[Comment]
--  一局游戏结束
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.onegameend(gameobj)
    local tableobj = gameobj.tableobj

    --保存结束时间
    tableobj.one_end_time = timetool.get_time()

	--清空计时器
	if tableobj.timer_id > 0 then
		timer.cleartimer(tableobj.timer_id)
		tableobj.timer_id = -1
	end

	--计算玩家当前得分和番数
	local noticemsgs = GameLogic.calculate_score_fancnt(gameobj)

    --更改每个座位总分
	for _, seat in pairs(tableobj.seats) do
		if not seatlogic.is_empty(seat) then
			seat.total_score = seat.total_score + seat.balance_score
		end
	end

    --发送大叫，花猪，退税消息
    if #noticemsgs > 0 then
        tableobj.wait_noticemsgs = noticemsgs
        tableobj.state = EMJTableState.TABLE_STATE_WAIT_ONE_GAME_REAL_END
        GameLogic.send_ts_dj_hz_msgs(tableobj)
        return
    end

    --设置桌子状态为：一局游戏真正结束
	tableobj.state = EMJTableState.TABLE_STATE_ONE_GAME_REAL_END
end

--[Comment]
--  一局游戏真正结束
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.onegamerealend(gameobj)
	local tableobj = gameobj.tableobj

    tableobj.is_onegameend = true
   
    --房卡场第一局结束扣房卡
    if tableobj.curr_to_num == 1 
    and tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then
        GameLogic.charge_service_fee(gameobj)
    end

     --通知结算金钱变化
    if tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI then
        GameLogic.game_balance_diamond(gameobj)
    elseif tableobj.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
        GameLogic.game_balance_dou(gameobj)
    elseif tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
        GameLogic.game_balance_coin(gameobj)
    end

    --保存牌局记录
    GameLogic.onegameend_save_tablerecord(gameobj)
    tablelogic.save_playback_record("end")          --本局回放记录结束
    
    --获得游戏结果
	local noticemsg = tabletool.deepcopy(GameLogic.get_game_result(gameobj))
    tableobj.game_records.cur_action_record_id = "" --本局操作记录日志id

    --重置桌子数据
	GameLogic.onegameend_inittable(gameobj)

    --将中途离桌的座位清空
    for _,seat in pairs(tableobj.seats) do
        if seat.has_leave then
            local rid,diamond = seat.rid,seat.playerinfo.diamond
	        tablelogic.passive_standuptable(tableobj, {}, seat, EStandupReason.STANDUP_REASON_ONSTANDUP)	
            tablelogic.passive_leavetable(tableobj,rid,diamond, true)
        end
    end
    
	--初始化桌位和保存当前局信息
    local cur_time = timetool.get_time()
	for _, seat in pairs(tableobj.seats) do
		if not seatlogic.is_empty(seat) then
            --重置座位数据
		    seatlogic.onegameend_initseat(seat)
            seat.ready_to_time = seat.ready_to_time or 30        --测试
            seat.ready_timeout_time = cur_time + seat.ready_to_time
		end
	end

    
    --获得重置之后的桌子信息,客户端清空桌子数据用
    noticemsg.table_gameinfo = tablelogic.copy_table_gameinfo()

     --发送结算
    tablelogic.sendmsg_to_alltableplayer(tableobj,"gamebalanceN",noticemsg)
   

    --房卡场，检测局数
	if tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then
        if tableobj.curr_to_num < tableobj.conf.retain_to_num then
            --设置桌子状态为：等待所有玩家准备
		    tableobj.state = EMJTableState.TABLE_STATE_WAIT_ALL_READY
	    else
            --局数已满，游戏结束
		    tableobj.state = EMJTableState.TABLE_STATE_GAME_END
            tableobj.end_time = timetool.get_time()             --结束时间
            --保存记录
            tableobj.game_records.delete_reason = EMJTableDeleteReason.DELETE_REASON_ATTAIN_TO_MAX_NUM

             --房卡场,发送游戏大结算
             if tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then
                GameLogic.game_balance_fangka(gameobj)
                GameLogic.send_game_end_result(gameobj)
            end

             --发送游戏结束
            GameLogic.send_gameend_notice(gameobj)
            return
	    end
    else
        tableobj.state = EMJTableState.TABLE_STATE_WAIT_ALL_READY
    end

    --设置了结束标记,删除桌子
    if tableobj.tableend_flag then
        skynet.call(tableobj.table_service,"lua","cmd","delete",EMJTableDeleteReason.DELETE_REASON_SYSTEM_REQUIRE)
        return
    end

    --通知所有玩家准备
    if tableobj.state == EMJTableState.TABLE_STATE_WAIT_ALL_READY then 
        for _, seat in pairs(tableobj.seats) do
            if not seatlogic.is_empty(seat) then
                if tableobj.conf.table_type ~= EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then  --钻石场，检查钱是否足够，不够则提示
                    local is_enough = GameLogic.check_player_money(tableobj,seat)
                    if not is_enough then
                        tablelogic.sendmsg_to_tableplayer(seat.rid, "notenoughmoneyN",{})
                    end

                    tablelogic.sendmsg_to_tableplayer(seat.rid, "doreadyN",{
                        action_timeout_time = seat.ready_timeout_time,
                    })
                    --机器人自动准备
                    if seat.is_robot then
                        timer.settimer(100,"robot_do_ready",{seat_index = seat.index})
                    end
                elseif tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then   --房卡场直接通知准备
                    tablelogic.sendmsg_to_tableplayer(seat.rid, "doreadyN",{
                        action_timeout_time = seat.ready_timeout_time,
                    })
                end
                local timer_id = timer.settimer(seat.ready_to_time * 100,"doready",{seat_index = seat.index,rid = seat.rid})
                seat.ready_timer_id = timer_id
            end
        end
    end
end

--[Comment]
--  解散游戏
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.disbandgame(gameobj)
	local tableobj = gameobj.tableobj

	if tableobj.timer_id > 0 then
		timer.cleartimer(tableobj.timer_id)
		tableobj.timer_id = -1
	end

    tableobj.end_time = timetool.get_time()             --结束时间
    if tableobj.is_onegameend or tableobj.curr_to_num > 1 then
	    GameLogic.send_game_end_result(gameobj)
    end
	GameLogic.onegameend_inittable(gameobj)

	tableobj.is_onegameend = true

	--初始化桌位和保存当前局信息
	for _, seat in pairs(tableobj.seats) do
		if not seatlogic.is_empty(seat) then
			seatlogic.onegameend_initseat(seat)
		end
	end

	tableobj.state = EMJTableState.TABLE_STATE_GAME_END
end

--[Comment]
--  游戏结束
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.gameend(gameobj)
	local tableobj = gameobj.tableobj

	tableobj.state = EMJTableState.TABLE_STATE_UNKNOW   --设置桌子状态为：未知
    if tableobj.game_records ~= nil then
	    tableobj.game_records.end_time = tableobj.end_time or timetool.get_time()
	    tableobj.game_records.final_to_num = tableobj.curr_to_num    --最终局数
        if tableobj.game_records.delete_reason == EMJTableDeleteReason.DELETE_REASON_IN_GAME_DISBAND then
            tableobj.game_records.final_to_num = tableobj.game_records.final_to_num - 1
        end
    end

	--强制踢掉玩家
    if tablelogic.get_sitdown_player_num(tableobj) > 0 then
		--踢出座位上的玩家
		tablelogic.leavetableallplayer(tableobj, EStandupReason.STANDUP_REASON_DELETE_TABLE)

		local waits = tabletool.deepcopy(tableobj.waits)
		for rid, waitinfo in pairs(waits) do
			tablelogic.passive_leavetable(tableobj, rid,waitinfo.playerinfo.diamond)
		end
	end

	--检查桌子当前是否能够删除
	if tableobj.delete_table_timer_id <= 0 then
		tableobj.delete_table_timer_id = -1
	end

    tableobj.is_had_start = false

    --倒计时删除,1s
    if tableobj.delete_table_timer_id == -1 then
        tableobj.delete_table_timer_id = timer.settimer(100, "delete_table")
    end
    if tableobj.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then
        tableobj.isdeleting = true
    end
end

--[Comment]
-- 获得金钱变化列表
--  tableobj
-- money_change_list
--
function GameLogic.get_money_change_list(tableobj, money_change_list, is_zuanshi)
    local cur_money_change_list = { }

    for _,item in pairs(money_change_list) do
        local cur_seat = tableobj.seats[item.index]
        local change_value = cur_seat.curr_score - item.begin_value
        if change_value ~= 0 then
            local money_list = {
                rid = item.rid,
                money_type = item.money_type,
                change_value = change_value,
            }
            if is_zuanshi then
                money_list.final_value = cur_seat.playerinfo.diamond + cur_seat.balance_score + cur_seat.curr_score
            elseif tableobj.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
                money_list.final_value = cur_seat.playerinfo.dou + cur_seat.balance_score + cur_seat.curr_score
            elseif tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
                money_list.final_value = cur_seat.playerinfo.coin + cur_seat.balance_score + cur_seat.curr_score
            else
                money_list.final_value = cur_seat.total_score + cur_seat.balance_score + cur_seat.curr_score
            end
            table.insert(cur_money_change_list,money_list)
            item.begin_value = cur_seat.curr_score
        end
    end

    return cur_money_change_list
end


--[Comment]
--  -计算所有玩家本局得分和番数
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.calculate_score_fancnt(gameobj)
	local tableobj = gameobj.tableobj
	local base_score = tableobj.conf.score_diamond or 0
    local dajiao_indexs = { }
    local huazhu_rids = { }         --花猪列表
    local dajiao_rids = { }         --大叫列表
    local tuisui_rids = { }         --退税列表
    local money_change_list = { }   --金币变化列表
    local is_zuanshi = false
    local noticemsgs = { }

    if tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI then
        is_zuanshi = true
    end

    --摸完所有手牌时：查大叫，查花猪
    if tableobj.cards_stack.cur_num == 0 and tableobj.is_liuju then
        --退税,未胡牌才退税
        for _,seat in pairs(tableobj.seats) do
            local item = { }
            item.rid = seat.rid
            item.index = seat.index
            item.begin_value = seat.curr_score
            item.money_type = (is_zuanshi and EMoneyType.DIAMOND) or EMoneyType.SCORE
            if tableobj.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
                item.money_type = EMoneyType.DOU or 4
            elseif tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
                item.money_type = EMoneyType.COIN or 3
            end
            table.insert(money_change_list,item)

            if not seat.is_hupai and not seat.is_giveup then
                seat.fan_types = {}
                local is_tingpai = cardtool.check_is_tingpai(seat.cards,false,seat.que_cardcolor,tableobj.is_7zhang)
                if not is_tingpai then  --查大叫（未听牌)
                    --退税
                    if GameLogic.tui_sui(gameobj,seat) then
                        seat.fan_types[EMJHuPaiType.HUPAI_TYPE_TUISUI] = true  --设置退税标记     
                        table.insert(tuisui_rids,seat.rid)
                    end
                    table.insert(dajiao_indexs,seat.index)
                    table.insert(dajiao_rids,seat.rid)
                end
            end
        end
        
        --通知退税
        if #tuisui_rids > 0 then
            table.insert(noticemsgs,{rids = tuisui_rids, msgname = "tuisuiN"})

            --通知客户端
            local cur_money_change_list = GameLogic.get_money_change_list(tableobj,money_change_list,is_zuanshi)
            if #cur_money_change_list > 0 then
                table.insert(noticemsgs,{money_change_list = cur_money_change_list, msgname = "moneychangeN"})
            end
        end

        --查花猪
        for _,seat in pairs(tableobj.seats) do
            if not seat.is_hupai and not seat.is_giveup then
                if cardtool.is_hua_zhu(seat.cards) then
                    GameLogic.hua_zhu(gameobj,seat)
                    seat.fan_types[EMJHuPaiType.HUPAI_TYPE_HUAZHU] = true  --设置花猪标记     
                    table.insert(huazhu_rids,seat.rid)
                end
            end
        end

        --通知查花猪
        if #huazhu_rids > 0 then
            table.insert(noticemsgs,{rids = huazhu_rids, msgname = "chahuazhuN"})

            --通知客户端
            local cur_money_change_list = GameLogic.get_money_change_list(tableobj,money_change_list,is_zuanshi)
            if #cur_money_change_list > 0 then
                table.insert(noticemsgs,{money_change_list = cur_money_change_list, msgname = "moneychangeN"})
            end
        end

        --查大叫
        for _,index in pairs(dajiao_indexs) do
            local cur_seat = tableobj.seats[index]
            if not cur_seat.fan_types[EMJHuPaiType.HUPAI_TYPE_HUAZHU] then  --花猪不用再赔
                GameLogic.da_jiao(gameobj,cur_seat)
            end
            cur_seat.fan_types[EMJHuPaiType.HUPAI_TYPE_DAJIAO] = true  --设置大叫标记
        end

        --通知查大叫
        if #dajiao_rids > 0 then
            table.insert(noticemsgs,{rids = dajiao_rids, msgname = "chadajiaoN"})

            --通知客户端
            local cur_money_change_list = GameLogic.get_money_change_list(tableobj,money_change_list,is_zuanshi)
            if #cur_money_change_list > 0 then
                table.insert(noticemsgs,{money_change_list = cur_money_change_list, msgname = "moneychangeN"})
            end
        end

        --反转
        if #noticemsgs > 0 then
            local tmp = { }
            for i = 1,#noticemsgs do
                local val = table.remove(noticemsgs)
                table.insert(tmp,val)
            end
            noticemsgs = tmp
        end

        --单次结算
        GameLogic.game_once_balance(gameobj)
    end

    --根据得分，计算胜负平数
    for _,seat in pairs(tableobj.seats) do
	    if seat.balance_score > 0 then
		    seat.win_num = seat.win_num + 1
	    elseif seat.balance_score < 0 then
		    seat.fail_num = seat.fail_num + 1
	    else
		    seat.draw_num = seat.draw_num + 1			
	    end		
    end
    
    --计算最终得分，并且赢家抽水
    local fee_rate = tableobj.service_fee_rate or 0
    for _,seat in pairs(tableobj.seats) do
        seat.real_change = seat.balance_score
        if seat.balance_score > 0 then --赢家抽水
            seat.balance_score = seat.balance_score - math.floor(seat.balance_score * 2 * fee_rate)
        end
    end

    return noticemsgs
end

--[Comment]
-- 初始化游戏记录(桌子创建时便被调用）
--
function GameLogic.init_game_records(tableobj)
    --游戏记录表（记录游戏数据）
    local service_fee = GameLogic.get_service_fee(tableobj)
	tableobj.game_records = { 
        --固定信息
        table_type = tableobj.table_type,               --桌子类型
		table_uuid = tableobj.uuid,                     --桌子uuid
        create_user_rid = tableobj.create_rid,          --创建者rid
        conf = tableobj.conf or { },                    --桌子配置
        service_fee = service_fee,                      --服务费
        delete_reason = 0,                              --删除原因
		create_time = tableobj.create_time,             --创建时间
        delete_time = 0,                                --删除时间
        start_time = 0,                                 --第一局开始时间
        end_time =  0,                                  --最后一局结束时间
		final_to_num = 0,                               --最终局数
        cur_action_record_id = "",                      --本局操作记录日志id
	}

end

--[Comment]
--游戏开始初始化牌局记录
--
function GameLogic.onegamestart_init_tablerecord(gameobj)
    local tableobj = gameobj.tableobj
    local rids = { }

    --每局信息
    tableobj.game_records.cur_record_id = ""                             --本局记录日志id（log日志文件名）
    tableobj.game_records.curr_to_num = tableobj.curr_to_num or 0        --当前局数
    tableobj.game_records.one_start_time = tableobj.one_start_time or 0  --本局开始时间
    tableobj.game_records.one_end_time = 0                               --本局结束时间
    tableobj.game_records.table_tradeid = ""                             --本局唯一交易id
    tableobj.game_records.balance_suan_fan_list = {}                     --本局结算算番情况：番型，杠牌，抓鸟等
    tableobj.game_records.all_player_action_list = {}                    --本局所有玩家的操作情况
    tableobj.game_records.player_init_cards_list = {}                    --本局手牌情况
    tableobj.game_records.banker_seat_index = tableobj.banker_seat_index or 0       --庄家位置
    tableobj.game_records.cards_stack = tabletool.deepcopy(tableobj.cards_stack)    --牌堆
    tableobj.game_records.player_que_card_color_list = {}                           --所有玩家缺牌花色列表
    tableobj.game_records.all_player_huansanzhang_list = {}                         --所有玩家换三张列表
    tableobj.game_records.dices_num_list = {}                                       --骰子点数数组
    tableobj.game_records.role_info = { }                                           --玩家信息

    --初始化玩家信息
    for _,seat in pairs(tableobj.seats) do
        if GameLogic.is_ingame(gameobj,seat) then
            local item = {
                sex = seat.playerinfo.sex,
                diamond = seat.playerinfo.diamond,
                coin = seat.playerinfo.coin,
                name = seat.playerinfo.rolename,
                logo = seat.playerinfo.logo,
                seat_index = seat.index,
             }
            tableobj.game_records.role_info[seat.rid] = item
        end
    end

    --本局操作记录日志id（log日志文件名）
    local cur_action_record_id = tableobj.uuid .. "_" .. tableobj.one_start_time .. "_" .. tableobj.one_end_time .. "_"
                     
    --玩家开始前金钱情况
    tableobj.game_records.diamond_change_list = {}  
    tableobj.game_records.coin_change_list = {}                                 
    for _,seat in pairs(tableobj.seats) do
        if GameLogic.is_ingame(gameobj,seat) then
            local item = { }
            item.gamestart_diamond = seat.playerinfo.diamond
            tableobj.game_records.diamond_change_list[seat.rid] = item
            tableobj.game_records.coin_change_list[seat.rid] = {gamestart_coin = seat.playerinfo.coin}
            table.insert(rids,seat.rid)
        end
    end

    --获得rid的升序序列
    table.sort(rids)
    tableobj.seq_rids = ""
    for _,rid in pairs(rids) do
        tableobj.seq_rids = tableobj.seq_rids .. rid .. "_"
    end
    cur_action_record_id = cur_action_record_id .. tableobj.seq_rids
    cur_action_record_id = cur_action_record_id .. os.date("%Y%m%d_%H%M%S",tableobj.one_start_time)
    if tableobj.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then
        cur_action_record_id = cur_action_record_id .. "_" .. EGameRoomType.ROOM_TYPE_ZIJIAN_FANGKA
    elseif tableobj.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI then
        if tableobj.is_matchtable then
            cur_action_record_id = cur_action_record_id .. "_" .. EGameRoomType.ROOM_TYPE_MATCH_ZUANSHI
        else
            cur_action_record_id = cur_action_record_id .. "_" .. EGameRoomType.ROOM_TYPE_ZIJIAN_ZUANSI
        end
    elseif tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
        cur_action_record_id = cur_action_record_id .. "_" .. EGameRoomType.ROOM_TYPE_MATCH_COIN
    end
    tableobj.game_records.cur_action_record_id = cur_action_record_id
end

--[Comment]
--游戏结束更新牌局记录
--
function GameLogic.onegameend_save_tablerecord(gameobj)
    local tableobj = gameobj.tableobj

    --修改牌局记录
	if tableobj.game_records ~= nil then
        local game_records = tableobj.game_records
        game_records.one_end_time = tableobj.one_end_time or 0
        game_records.table_tradeid = tableobj.cur_table_tradeid or ""
        
        --钻石变化
        local record_id = game_records.table_uuid .. "_"
        record_id = record_id .. game_records.one_start_time .. "_"
        record_id = record_id .. game_records.one_end_time .. "_"
        record_id = record_id .. tableobj.seq_rids
        for _,seat in pairs(tableobj.seats) do
            if GameLogic.is_ingame(gameobj, seat) then
                --金钱变化
                local ditem = game_records.diamond_change_list[seat.rid] or { }
                local citem = game_records.coin_change_list[seat.rid] or { }
                ditem.winvalue = seat.playerinfo.diamond - ditem.gamestart_diamond
                citem.winvalue = seat.playerinfo.coin - citem.gamestart_coin
                ditem.gameend_diamond = seat.playerinfo.diamond
                citem.gameend_coin = seat.playerinfo.coin
                
                --结算相关
                local suan_fan_list = { }

                --番型
                suan_fan_list.fan_types = tabletool.deepcopy(seat.fan_types)
				--胡牌类型
                suan_fan_list.hupai_type = seat.hupai_type
                --碰杠牌
                suan_fan_list.di_cards = tabletool.deepcopy(seat.di_cards)        
                --是否胡牌
                suan_fan_list.is_hupai = seat.is_hupai
                --是否认输
                suan_fan_list.is_giveup = seat.is_giveup
                --引胡玩家座位
                suan_fan_list.yinhu_seat_index = seat.yinhu_seat_index
                --胡的牌
                suan_fan_list.hupai_card = seat.hupai_card
                --最终手牌
                suan_fan_list.final_cards = tabletool.deepcopy(seat.cards)
                --本局得分
                suan_fan_list.curr_score = seat.balance_score
                --缺牌花色
                suan_fan_list.que_cardcolor = seat.que_cardcolor
                --座位号
                suan_fan_list.seat_index = seat.index
                --战胜玩家的座位号
                suan_fan_list.win_seat_indexs = tabletool.deepcopy(seat.winhupai_fan_info)
                game_records.balance_suan_fan_list[seat.rid] = suan_fan_list
            end
        end
        record_id = record_id .. os.date("%Y%m%d_%H%M%S",game_records.one_start_time)
        if tableobj.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then
            record_id = record_id .. "_" .. EGameRoomType.ROOM_TYPE_ZIJIAN_FANGKA
        elseif tableobj.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI then
            if tableobj.is_matchtable then
                record_id = record_id .. "_" .. EGameRoomType.ROOM_TYPE_MATCH_ZUANSHI
            else
                record_id = record_id .. "_" .. EGameRoomType.ROOM_TYPE_ZIJIAN_ZUANSI
            end
        elseif tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
            if tableobj.is_matchtable then
                record_id = record_id .. "_" .. EGameRoomType.ROOM_TYPE_MATCH_COIN
            else
                record_id = record_id .. "_" .. EGameRoomType.ROOM_TYPE_ZIJIAN_COIN
            end
        end
        game_records.cur_record_id = record_id
	end
    
    --写到日志
    --tablelogic.save_table_records(tableobj.game_records)
    tablelogic.save_playback_record(tableobj.game_records.balance_suan_fan_list)

end

-----------------------------------------------------------------------------
---check类
--

--[Comment]
--  检查是否所有玩家完成操作，未完成时的最高优先级的操作类型
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.check_end_action(gameobj)
    local tableobj = gameobj.tableobj

	local is_all = true             --是否所有玩家都操作结束
	local max_had_action_type = 0   --当前最大操作动作类型（最高优先级的）
    local max_had_action = nil
    local tmp_action = nil
    local is_no_hupai = false
    local max_action_type = 0       --最大操作类型
    local max_action = nil

    if tableobj.action_player_list == nil then
        return true
    end

    --遍历玩家操作列表，判断每个玩家所有操作（当前操作和待操作列表）
	for _, player_action in pairs(tableobj.action_player_list) do
        --是否有玩家有未操作动作
		if player_action.action_state == EMJActionState.NODO then
			is_all = false
		end

        --检测是否有未胡牌操作
        if not is_no_hupai then
            local cur_max = 0
            if player_action.action_state == EMJActionState.NODO then
                for _,act in pairs(player_action.wait_action_types) do
                    if cur_max < act then
                        cur_max = act
                    end
                    if act == EMJActionType.MJ_ACTION_TYPE_HUPAI then
                        is_no_hupai = true
                        break
                    end
                end
            else
                cur_max = player_action.action_type
            end

            if max_action_type < cur_max then
                max_action_type = cur_max
                max_action = player_action
            end
        end

        --保存当前最大操作类型，hupai操作优先级最高
		if player_action.action_type ~= EMJActionType.MJ_ACTION_TYPE_SELECT 
        and max_had_action_type < player_action.action_type then
			max_had_action_type = player_action.action_type
            max_had_action = player_action
		end
        tmp_action = player_action
	end

    --返回：是否都操作完成，当前最大待操作类型
    --如果都操作，返回最高优先级的操作作为结果，胡 > 碰、杠 > 过
    --如果还有未操作的，等待客户端操作

    --最大可操作类型：胡牌
    if max_had_action == nil then
        max_had_action = tmp_action
    end

    --最高优先级的操作过后，且不为过时，不等其他操作
    if not is_no_hupai and not is_all then
        if max_had_action.rid == max_action.rid then
            if max_had_action.action_state ~= EMJActionState.NODO then
                is_all = true

                --将其他操作全置为过
                for _, player_action in pairs(tableobj.action_player_list) do
                    if player_action.action_type == EMJActionType.MJ_ACTION_TYPE_SELECT
                    and player_action.action_state == EMJActionState.NODO then
                        player_action.action_type = EMJActionType.MJ_ACTION_TYPE_GUO
                        player_action.action_state = EMJActionState.DOING
                    end
                end
            end
        end
    end

	return is_all, max_had_action 
end

--[Comment]
--  检查玩家钱是否足够
--  gameobj 游戏对象，{stateevent,tableobj}
--
function  GameLogic.check_player_money(tableobj,seat)
    tableobj.conf.leave_diamond = tableobj.conf.leave_diamond or 0
    if not seat then
        return false
    end

    local service_fee = GameLogic.get_service_fee(tableobj)
    local money = seat.playerinfo.diamond
    if tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
        money = money + seat.playerinfo.coin
        if seat.playerinfo.coin < service_fee then
            return false
        end
    end
    
    if money < service_fee or money <= tableobj.conf.leave_diamond then
        return false
    end

    return true
end

--[Comment]
--  检查是否为过胡牌
--
function GameLogic.check_is_guohu_card(seat,cur_card)
    if seat.is_guohu and seat.guohu_cards then
        for _,card in pairs(seat.guohu_cards) do
            if card == cur_card then
                local last_max_fan = seat.guohu_max_fan  or 0
                local cur_max_fan = seat.fan_types[seat.fan_types.max_type] or 0
                if cur_max_fan > last_max_fan then
                    --return false
                end
                return true
            end
        end
    end
    
    return false
end

------------------------------------------------------------------------
--通知类方法
--

--[Comment]
--  通知所有玩家游戏开始
--  gameobj 游戏对象，{stateevent,tableobj}
--
 function GameLogic.send_gamestart_notice(gameobj)
	local tableobj = gameobj.tableobj
	local noticemsg = { }

	noticemsg.countdown_time = tableobj.countdown_time          --游戏开始倒计时
    noticemsg.banker_seat_index = tableobj.banker_seat_index    --庄家位置
    noticemsg.curr_to_num = tableobj.curr_to_num                --当前局数
    noticemsg.curr_round_code = tableobj.curr_round_code        --当前局号
    noticemsg.seat_roleinfos = { }
    noticemsg.seat_gameinfos = { }
    for index,seat in pairs(tableobj.seats) do
		noticemsg.seat_roleinfos[index] = tablelogic.copy_seat_roleinfo(seat)
		noticemsg.seat_gameinfos[index] = tablelogic.copy_seat_gameinfo(seat)
	end
	tablelogic.sendmsg_to_alltableplayer(tableobj,"gamestartN", noticemsg)
 end

--[Comment]
--  通知所有玩家一局游戏结束
--  gameobj 游戏对象，{stateevent,tableobj}
--
 function GameLogic.send_onegameend_notice(gameobj)
	local tableobj = gameobj.tableobj
	local noticemsg = { }

    noticemsg.table_index = tableobj.index    --桌号
	tablelogic.sendmsg_to_alltableplayer(tableobj,"onegameendN", noticemsg)
 end

 --[Comment]
--  通知所有玩家游戏结束
--  gameobj 游戏对象，{stateevent,tableobj}
--
 function GameLogic.send_gameend_notice(gameobj)
	local tableobj = gameobj.tableobj
	local noticemsg = { }

    noticemsg.table_index = tableobj.index    --桌号
	tablelogic.sendmsg_to_alltableplayer(tableobj,"gameendN", noticemsg)
 end

--[Comment]
--  通知庄家摇骰子
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.send_shakedice_notice(gameobj)
	local tableobj = gameobj.tableobj
	local seat = tableobj.seats[tableobj.banker_seat_index]
	local noticemsg = {
		rid = seat.rid,
		seat_index = seat.index,
		dice_one = tableobj.dice_one,		
		dice_two = tableobj.dice_two,
	}

	tablelogic.sendmsg_to_tableplayer(seat.rid,"shakediceN", noticemsg)
    --noticemsg.dice_one = nil
    --noticemsg.dice_two = nil
    tablelogic.sendmsg_to_otheralltableplayer(tableobj,seat.rid,"shakediceN", noticemsg)
end

--[Comment]
--  通知所有玩家服务器发牌
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.send_dealcards_notice(gameobj)
	local tableobj = gameobj.tableobj
	local index = nil
	local seat = nil
	local noticemsg = { }

    --首先通知庄家，然后顺位依次通知其他玩家
	for i = 0, tableobj.conf.max_player_num - 1 do
        --获得座位索引
		index = (tableobj.banker_seat_index + i) % tableobj.conf.max_player_num
		if index == 0 then
			index = tableobj.conf.max_player_num
		end

        --获得座位
		seat = tableobj.seats[index]
		if GameLogic.is_ingame(gameobj, seat) then  --判断是否在游戏中
			noticemsg.rid = seat.rid
			noticemsg.seat_index = seat.index   --座位号
			noticemsg.cards = tabletool.deepcopy(seat.cards)         --手牌，牌已经发好了的
			noticemsg.remain_card_num = tableobj.cards_stack.cur_num --牌堆剩余牌张数

            --通知当前玩家
			tablelogic.sendmsg_to_tableplayer(seat.rid, "dealcardsN", noticemsg)  
		end
	end
end

--[Comment]
--  通知游戏结束结算信息，大结算
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.send_game_end_result(gameobj,is_notsendto_client)
    local tableobj = gameobj.tableobj

	--通知游戏结算
	local noticemsg = {
		table_index = tableobj.index,                   --桌子id
        create_rid = tableobj.create_rid,               --创建者rid
        create_rolename = tableobj.create_rolename,     --创建者名字
		retain_to_num = tableobj.conf.retain_to_num,    --最大局数
		curr_to_num = tableobj.curr_to_num,             --当前局数
		is_gameend = true,                              --是否游戏结束
		start_time = tableobj.start_time,               --本桌开始时间
        end_time = tableobj.end_time,                   --本桌结束时间
		table_type = tableobj.conf.table_type,          --桌子类型
		playergamerecordlist = {                        --所有玩家的结算列表
		}
	}

    --获得每个座位结算信息
	local playergamerecorditem
	for index, seat in pairs(tableobj.seats) do
		if not seatlogic.is_empty(seat) then
			playergamerecorditem = {   --结算信息
				rid = seat.rid,
				rolename = seat.playerinfo.rolename,
				logo = seat.playerinfo.logo,
	 			total_score = seat.total_score, --总得分
                win_num = seat.win_num,		    --记录玩家胜利次数
	            fail_num = seat.fail_num,   	--记录玩家失败次数
	            draw_num = seat.draw_num,   	--记录玩家平局数
	            lottery_num = seat.lottery_num, --奖券数
				max_fan_cnt = seat.max_fan_cnt, --最大番数
			}
            table.insert(noticemsg.playergamerecordlist, playergamerecorditem)	
         end	
	end

    --未通知客户端，则通知
	if not is_notsendto_client then
		tablelogic.sendmsg_to_alltableplayer(tableobj,"tablebalanceN", noticemsg)
	end

    --保存记录
	
end

------------------------------------------------------------------------
---修改数据类
--

--[Comment]
-- 第一局游戏开始时，初始化桌子
--
function GameLogic.gamestart_inittable(gameobj)
    --tableobj即table_data
	local tableobj = gameobj.tableobj

    --初始化桌子数据
	tableobj.end_time = 0                       --桌子结束时间
    tableobj.start_time = timetool.get_time()   --游戏开始时间
	tableobj.is_will_delete = 0                 --是否将被删除,1表示true,0表示false
	tableobj.is_onegameend = false              --是否一局游戏结束
	tableobj.cards_stack = { }                  --当前牌堆
    tableobj.last_banker_seat_index = 0         --上局庄家
    tableobj.last_ypdx_seat_index = 0           --上局一炮多响位置
    tableobj.last_hupai_seat_index = 0          --上局胡牌位置

    --保存游戏记录
    if tableobj.game_records then
        tableobj.game_records.start_time = tableobj.start_time
    end
end

--[Comment]
-- 重置桌子数据
--
function GameLogic.reset_tabledata(gameobj)
	local tableobj = gameobj.tableobj

    if tableobj.has_resettable then
        return
    end

    --初始化桌子数据
	tableobj.end_time = 0                       --桌子结束时间
	tableobj.is_will_delete = 0                 --是否将被删除,1表示true,0表示false
	tableobj.is_onegameend = false              --是否一局游戏结束
    tableobj.last_banker_seat_index = 0         --上局庄家
    tableobj.last_ypdx_seat_index = 0           --上局一炮多响位置
    tableobj.last_hupai_seat_index = 0          --上局胡牌位置
    tableobj.has_resettable = true
end

--[Comment]
-- 每局游戏开始时，初始化桌子
--
function GameLogic.onegamestart_inittable(gameobj)
	local tableobj = gameobj.tableobj
	local now = timetool.get_time()

	tableobj.one_start_time =  now          --本局开始时间
    tableobj.one_end_time = 0               --本局结束时间

    --本局局号
    tableobj.curr_round_code = string.format("%04d",now % 10000)

	tableobj.banker_seat_index = 0              --当前庄家位置
	tableobj.ypdx_seat_index = 0                --当前局一炮多响位置
	tableobj.hupai_seat_index = 0               --当前局首先胡牌玩家位置

	tableobj.action_timeout_time = 0            --当前操作超时时间
    tableobj.ready_outtime_time = 0             --准备超时时间

    --当前出牌位置信息
	tableobj.chu_mo_pai_seat_index = 0          --当前出摸牌位置
	tableobj.chu_mo_pai_card = 0                --出摸的牌
	tableobj.chu_mo_paitag = 0                  --出摸牌类型

    --当前操作信息（杠碰胡过，出牌）
	tableobj.curr_action_seat_index = 0         --当前操作玩家位置
    tableobj.curr_actionplayer_rid = 0          --当前操作玩家的rid
	tableobj.curr_actionplayer_cards = nil      --当前操作的牌
	tableobj.curr_actionplayer_cardcolor = 0    --当前操作牌的花色
	tableobj.curr_gangpai_seat_index = 0        --记录当前杠牌座位号
	tableobj.curr_gangpai_info = nil            --记录当前杠牌信息

    --出牌次数，每出一张牌，记录一次
	tableobj.chupai_count = 0                   --记录出牌次数

    --一局结束的标记
	tableobj.is_onegameend = false              --是否一局结束
    tableobj.is_ingame = true                   --是否游戏中

	--当前所有可操作玩家的动作列表（碰杠胡可能有多家）
	tableobj.action_player_list = nil           --玩家待执行动作列表

    --初始化座位
    for _,seat in pairs(tableobj.seats) do
        if not seatlogic.is_empty(seat) then
            seatlogic.onegamestart_initseat(seat)
        end
    end
    
    --重置通用计时器
	if tableobj.timer_id >= 0 then
		timer.cleartimer(tableobj.timer_id)
		tableobj.timer_id = -1
	end

    tableobj.dice_one = 0                   --骰子1点数
	tableobj.dice_two = 0                   --骰子2点数

    tableobj.cards_stack = { }
    tableobj.huansanzhang_list = { }
    tableobj.que_color_list = { }       --缺牌花色列表
    tableobj.is_liuju  = nil

    tableobj.cur_balance_score_list = { }
    tableobj.has_resettable = nil
    tableobj.win_diamond_list = nil
    tableobj.gangpai_score_list = nil
    
    --重新获取抽水率
    local gamename = tablelogic.get_gamename(tableobj)
    local cur_rate = slottool.get_service_fee_rate_from_redis(gamename)
    if cur_rate then
        tableobj.service_fee_rate = tonumber(cur_rate) or 0.035
    end
end

--[Comment]
-- 每局游戏结束时，初始化桌子
--
function GameLogic.onegameend_inittable(gameobj)
	local tableobj = gameobj.tableobj

    --必须保存本局胡牌位置，方便计算下局庄家
	tableobj.last_banker_seat_index = tableobj.banker_seat_index    --上一个庄家位置
	tableobj.last_ypdx_seat_index = tableobj.ypdx_seat_index        --上一局一炮多响位置
	tableobj.last_hupai_seat_index = tableobj.hupai_seat_index      --上局首先胡牌玩家位置

    tableobj.one_start_time = 0	      --开始时间要先清空，游戏开始时再设置
    tableobj.is_ingame = false        --是否游戏中
    tableobj.curr_round_code = ""

    ------------
    --以下每局开始时也会被初始化
	tableobj.action_timeout_time = 0

	tableobj.chu_mo_pai_seat_index = 0
	tableobj.chu_mo_pai_card = 0
	tableobj.chu_mo_paitag = 0

	--当前操作信息（杠碰胡过，出牌）
	tableobj.curr_action_seat_index = 0         --当前操作玩家位置
    tableobj.curr_actionplayer_rid = 0          --当前操作玩家的rid
	tableobj.curr_actionplayer_cards = nil      --当前操作的牌
	tableobj.curr_actionplayer_cardcolor = 0    --当前操作牌的花色
	tableobj.curr_gangpai_seat_index = 0        --记录当前杠牌座位号
	tableobj.curr_gangpai_info = nil            --记录当前杠牌信息

	tableobj.chupai_count = 0                   --记录出牌次数

    tableobj.action_player_list = nil
    tableobj.huansanzhang_list = nil
    tableobj.que_color_list = nil
    tableobj.is_liuju  = nil
 
    --初始化座位
    for _,seat in pairs(tableobj.seats) do
        if not seatlogic.is_empty(seat) then
            seatlogic.onegameend_initseat(seat)
        end
    end

    if tableobj.timer_id >= 0 then
		timer.cleartimer(tableobj.timer_id)
		tableobj.timer_id = -1
	end

    --钻石场保存初始钻石数
    tableobj.init_diamond_list = {}
    tableobj.win_diamond_limits = {}
    tableobj.cur_balance_score_list = { }
    tableobj.win_diamond_list = nil
    tableobj.curr_seats_money = {}
    tableobj.gangpai_score_list = nil
end

-----------------------------------------------------------
--clear类
--

--[Comment]
--清除出摸牌状态
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.clear_chumo_state(gameobj)
	local tableobj = gameobj.tableobj
	tableobj.chu_mo_pai_card = 0
	tableobj.chu_mo_paitag = EMJActionType.MJ_ACTION_TYPE_UNKNOW
	tableobj.chu_mo_pai_seat_index = 0
end

--[Comment]
--清除上一次杠牌信息
--
function GameLogic.clear_gangpai_state(gameobj)
	local tableobj = gameobj.tableobj
	tableobj.curr_gangpai_seat_index = 0 --记录当前杠牌座位号
	tableobj.curr_gangpai_info = nil     --记录当前杠牌信息	
end

--[Comment]
--清除桌子的当前操作状态
--
function GameLogic.clear_action_state(gameobj)
	local tableobj = gameobj.tableobj
	tableobj.action_player_list = nil       --清空当前操作玩家列表
	tableobj.curr_actionplayer_rid = 0      
	tableobj.curr_actionplayer_cards = nil  --记录当前操作牌
end

--[Comment]
--清除过手胡状态
--
function GameLogic.clear_guohu_state(gameobj,action_seat_index)
	local tableobj = gameobj.tableobj
	for _,seat in pairs(tableobj.seats) do
	    if seat.guohu_seat_index ~= nil then
            if action_seat_index == seat.guohu_seat_index then
                seat.guohu_seat_index = nil
                seat.is_guohu = nil
                seat.guohu_cards = nil
                seat.guohu_max_fan = nil
            end
        end
	end
end

--[Comment]
-- 站起后，删除座位对象
--
function GameLogic.standup_clear_seat(gameobj, seat)
	seatlogic.clear_seat(seat)
end

---------------------------------------------------------------
---is类
--

--[Comment]
--判断座位对应玩家是否在游戏中
--
function GameLogic.is_ingame(gameobj, seat)
	return (seat.state == EMJSeatState.SEAT_STATE_PLAYING)
end

--[Comment]
--判断当前局游戏是否能够结束
--
function GameLogic.is_onegame_canend(gameobj)
	local tableobj = gameobj.tableobj

    --只剩一家未胡或未认输，可结束
	local hupai_player_num = 0
	for _, seat in pairs(tableobj.seats) do
		if seat.is_hupai or seat.is_giveup then
			hupai_player_num = hupai_player_num + 1
		end
	end

	if hupai_player_num >= tableobj.conf.max_player_num - 1 then
		return true
	end

    --牌摸完，可结束
	if tableobj.cards_stack.cur_num <= 0 then
        tableobj.is_liuju = true
		return true
	end

	return false 
end

------------------------------------------------------------
---get类
--

--[Comment]
--  获得回合数
-- 算出的值并不准确,只是用于判断天地胡
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.get_round_num(gameobj)
    local tableobj = gameobj.tableobj
    local max_player = tableobj.conf.max_player_num or 2
    local round_num = math.floor(tableobj.chupai_count / max_player)
    if tableobj.chupai_count % max_player ~= 0 then
        round_num = round_num + 1
    end 

    return round_num
end

--[Comment]
--  通知结算信息
--  gameobj 游戏对象，{stateevent,tableobj}
--
function GameLogic.get_game_result(gameobj)
	local tableobj = gameobj.tableobj

	--通知游戏结算
	local noticemsg = {
		table_index = tableobj.index,                   --桌子id
        create_rid = tableobj.create_rid,               --创建者rid
        create_rolename = tableobj.create_rolename,     --创建者名字
		retain_to_num = tableobj.conf.retain_to_num,    --最大局数
		curr_to_num = tableobj.curr_to_num,             --当前局数
		is_gameend = false,                             --是否游戏结束
		one_start_time = tableobj.one_start_time,       --本局开始时间
        one_end_time = tableobj.one_end_time,           --本局结束时间
		table_type = tableobj.conf.table_type,          --桌子类型
        banker_seat_index = tableobj.banker_seat_index, --庄家位置
		playergameresultlist = {                        --所有玩家的结算列表
		}

	}
	if tableobj.game_records ~= nil then
		noticemsg.record_id = tableobj.game_records.cur_record_id  --本局记录数据的id
	end

    --局数达到最大，或则桌子状态为解散游戏，设置游戏状态为结束
    if tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then
	    if noticemsg.retain_to_num <= noticemsg.curr_to_num 
		or tableobj.state == EMJTableState.TABLE_STATE_DISBAND_GAME then
		    noticemsg.is_gameend = true
	    end
    end
	
    --获得每个座位结算信息
	local playergameresultitem
	local is_find = false
	for index, seat in pairs(tableobj.seats) do
		is_find = false
		if GameLogic.is_ingame(gameobj, seat) then
			playergameresultitem = {   --结算信息
				rid = seat.rid,
                seat_index = seat.index,
				rolename = seat.playerinfo.rolename,
				logo = seat.playerinfo.logo,
				curr_score = seat.balance_score,
	 			total_score = seat.total_score,
				hupai_card = seat.hupai_card,   --胡的牌
				cards = seat.cards,             --手牌
				di_cards = seat.di_cards,       --碰杠牌
                out_cards = seat.out_cards,     --已出牌
				fan_types = {},                 --番型数组
				fan_cnt = seat.fan_cnt,         --番数
				win_players = {},               --战胜玩家列表
				is_hupai = seat.is_hupai,       --是否胡牌
				yinhu_seat_index = seat.yinhu_seat_index,   --引胡座位号
			}

            if seat.is_hupai and seat.yinhu_seat_index ~= seat.index 
            and not seat.fan_types[EMJHuPaiType.HUPAI_TYPE_DIAN_GANG_HUA] then
                table.insert(playergameresultitem.cards,seat.hupai_card)
            end

            --设置番型
			if seat.fan_types ~= nil then
                if seat.is_hupai then
                    table.insert(playergameresultitem.fan_types, seat.hupai_type)
                end
				for fan_type,val in pairs(seat.fan_types) do
                    if type(val) == "boolean" and seat.hupai_type ~= fan_type 
                    and fan_type ~= EMJHuPaiType.HUPAI_TYPE_DIAN_GANG_HUA then
				        table.insert(playergameresultitem.fan_types, fan_type)
                    end
				end
            end
			
            --获得战胜玩家列表（仅包含战胜玩家名字）
			if seat.is_hupai and seat.winhupai_fan_info then
				for _, seat_index in pairs(seat.winhupai_fan_info) do
                    local tmp_seat = tableobj.seats[seat_index]
					table.insert(playergameresultitem.win_players, tmp_seat.playerinfo.rolename)
				end
			end
			table.insert(noticemsg.playergameresultlist, playergameresultitem)		
		end	
	end

    return noticemsg
end

--[Comment]
--  获得服务费
--
function GameLogic.get_service_fee(tableobj)
    local service_charge = 0
    local score_diamond = tableobj.conf.score_diamond or 0

    if tableobj.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI then
        service_charge = math.floor(0.3 * score_diamond)
    elseif tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
        service_charge = 10
    end

    return service_charge
end

--[Comment]
--获得游戏中玩家数
--
function GameLogic.get_ingame_playernum(gameobj)
	local tableobj = gameobj.tableobj
	local playernum = 0
	for _, seat in pairs(tableobj.seats) do
		if GameLogic.is_ingame(gameobj, seat) then
			playernum = playernum + 1
		end
	end
	return playernum
end

------------------------------------------------------------
---结算类
--

--[Comment]
--杠牌结算
--杠了立马结算，牌局结束有可能退税
--gang_seat_index 杠牌座位号
--yin_gang_seat_index 引杠座位号
--
function GameLogic.settle_gang_pai(gameobj,gang_seat_index,yin_gang_seat_index,gang_type)
    local tableobj = gameobj.tableobj
    local is_zuanshi = false
    local win_seat_indexs = { }
    local rids = { }
    local noticemsg = {
        money_change_list = { },
    }

    if not gameobj or gang_type == nil then
        return false
    end

    if tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI then
        is_zuanshi = true
    end

    --初始分数
    local begin_scores = { }
    for _,s in pairs(tableobj.seats) do
        begin_scores[s.rid] = s.balance_score
    end

    local base_score = tableobj.conf.score_diamond or 0 --底注
    local gang_seat = tableobj.seats[gang_seat_index]

    --当前结算分数列表
    tableobj.cur_balance_score_list = tableobj.cur_balance_score_list or { }
    tableobj.cur_balance_score_list[gang_seat.rid] = tableobj.cur_balance_score_list[gang_seat.rid] or { }
    local score_list = tableobj.cur_balance_score_list[gang_seat.rid]

    if gang_type == EMJActionType.MJ_ACTION_TYPE_ZHIGANG then       --明杠：赢引杠玩家2倍底分
        local yin_gang_seat = tableobj.seats[yin_gang_seat_index]
        gang_seat.curr_score = gang_seat.curr_score + 2 * base_score
        yin_gang_seat.curr_score = yin_gang_seat.curr_score - 2 * base_score
        table.insert(win_seat_indexs,yin_gang_seat_index)
        rids[gang_seat.rid] = true
        rids[yin_gang_seat.rid] = true
        score_list[yin_gang_seat.index] = (score_list[yin_gang_seat.index] or 0) + 2 * base_score
    elseif gang_type == EMJActionType.MJ_ACTION_TYPE_ANGANG then    --暗杠：赢其他三家2倍底分
        local cnt = 0
        for _,seat in pairs(tableobj.seats) do
            if GameLogic.is_ingame(gameobj, seat) and seat.rid ~= gang_seat.rid and not seat.is_hupai and not seat.is_giveup then
                seat.curr_score = seat.curr_score - 2 * base_score
                cnt = cnt + 1
                table.insert(win_seat_indexs,seat.index)
                rids[seat.rid] = true
                score_list[seat.index] = (score_list[seat.index] or 0) + 2 * base_score
            end
        end
        gang_seat.curr_score = gang_seat.curr_score + cnt * 2 * base_score
        rids[gang_seat.rid] = true
    elseif gang_type == EMJActionType.MJ_ACTION_TYPE_BAGANG then    --补杠：赢其他三家1倍底分
        local cnt = 0
        for _,seat in pairs(tableobj.seats) do
            if GameLogic.is_ingame(gameobj, seat) and seat.rid ~= gang_seat.rid and not seat.is_hupai and not seat.is_giveup then
                seat.curr_score = seat.curr_score - 1 * base_score
                cnt = cnt + 1
                table.insert(win_seat_indexs,seat.index)
                rids[seat.rid] = true
                score_list[seat.index] = (score_list[seat.index] or 0) + base_score
            end
        end
        gang_seat.curr_score = gang_seat.curr_score + cnt * base_score
        rids[gang_seat.rid] = true
    end

    --单次结算
    local end_scores = GameLogic.game_once_balance(gameobj)

    --通知客户端，实际数据未生效
    for _,seat in pairs(tableobj.seats) do
        local item = { rid = seat.rid, }
        if rids[seat.rid] then
            item.money_type = (is_zuanshi and EMoneyType.DIAMOND) or EMoneyType.SCORE
            local total_change = end_scores[seat.rid] - begin_scores[seat.rid]
            if is_zuanshi then
                item.final_value = seat.playerinfo.diamond + seat.balance_score
            elseif tableobj.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
                item.money_type = EMoneyType.DOU or 4
                item.final_value = seat.playerinfo.dou + seat.balance_score
            elseif tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
                item.money_type = EMoneyType.COIN or 3
                item.final_value = seat.playerinfo.coin + seat.balance_score
                if item.final_value < 0 then    --不够扣
                    local ditem =  {
                        rid = seat.rid,
                        money_type = EMoneyType.DIAMOND,
                    }
                    
                    local begindiamond = seat.playerinfo.diamond
                    local begincoin = seat.playerinfo.coin + begin_scores[seat.rid]
                    if begincoin < 0 then
                        begindiamond = begindiamond + begincoin
                        begincoin = 0
                    end
                    ditem.change_value = total_change + begincoin
                    ditem.final_value = begindiamond + ditem.change_value
                    total_change = -begincoin
                    table.insert(noticemsg.money_change_list,ditem)
                    item.final_value = 0
                end
            else
                item.final_value = seat.total_score + seat.balance_score
            end
            item.change_value = total_change
            table.insert(noticemsg.money_change_list,item)
        end
    end
    tablelogic.sendmsg_to_alltableplayer(tableobj,"moneychangeN",noticemsg)

    --保存杠牌结算数据，方便退税
    tableobj.gangpai_score_list = tableobj.gangpai_score_list or {}
    tableobj.gangpai_score_list[gang_seat.rid] = tableobj.gangpai_score_list[gang_seat.rid] or {}
    local gp_score_list = tableobj.gangpai_score_list[gang_seat.rid]
    for _,tmpseat in pairs(tableobj.seats) do
        gp_score_list[tmpseat.index] = (gp_score_list[tmpseat.index] or 0) + (end_scores[tmpseat.rid] - begin_scores[tmpseat.rid])
    end

    return win_seat_indexs
end

--[Comment]
--@ des 单次结算，每次扣费都做一次结算
--@ gameobj 游戏对象
--@ hu_seat 胡牌玩家座位
--
function GameLogic.game_once_balance(gameobj)
    local tableobj = gameobj.tableobj

    --检测输赢上限
    if tableobj.is_limit_win_or_lose then
        if tableobj.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI 
        or tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG
        or tableobj.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
            GameLogic.check_limit_of_winorlose(tableobj)
        end
    end

    --保存结算分
    local begin_scores = { }
    local end_scores = { }
    for i,seat in pairs(tableobj.seats) do
        begin_scores[seat.rid] = seat.balance_score
        seat.balance_score = seat.balance_score + seat.curr_score
        tableobj.init_diamond_list[seat.rid] = tableobj.init_diamond_list[seat.rid] + seat.curr_score   --输上限
        tableobj.win_diamond_limits[seat.rid] = tableobj.win_diamond_limits[seat.rid] - seat.curr_score --赢上限
        seat.curr_score = 0
        end_scores[seat.rid] = seat.balance_score
    end
    tableobj.back_balance_score_list = tableobj.cur_balance_score_list
    tableobj.cur_balance_score_list = { }

    --金豆场检测是否扣金币
    GameLogic.check_is_balance_diamond(tableobj, begin_scores)

    return end_scores
end

--[Comment]
--金豆场检测是否需要结算金豆
--
function GameLogic.check_is_balance_diamond(tableobj, begin_scores)
    if tableobj.table_type ~= EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
        return
    end
    local curr_seats_money = tableobj.curr_seats_money

    local coin_values = { }
    local diamond_values = nil
    local rid_to_index = { }
    for i,seat in pairs(tableobj.seats) do
        local begincoin = curr_seats_money[seat.rid].coin
        local begindiamond = curr_seats_money[seat.rid].diamond
        local change_value = seat.balance_score - begin_scores[seat.rid]
        if begincoin <= 0 then
            begindiamond = begindiamond + begincoin
            begincoin = 0
        end

        coin_values[seat.rid] = {}
        coin_values[seat.rid].beginvalue = begincoin
        coin_values[seat.rid].value = change_value
        coin_values[seat.rid].endvalue = begincoin + change_value
        rid_to_index[seat.rid] = i
        --金豆不够，扣金豆
        if coin_values[seat.rid].endvalue < 0 then
            diamond_values = diamond_values or { }
            diamond_values[seat.rid] = { }
            diamond_values[seat.rid].beginvalue = begindiamond
            diamond_values[seat.rid].value = coin_values[seat.rid].endvalue
            diamond_values[seat.rid].endvalue = begindiamond + diamond_values[seat.rid].value
            coin_values[seat.rid].endvalue = 0
            coin_values[seat.rid].value = -begincoin
        end
    end

    --修复金豆结算
    if diamond_values then
        GameLogic.fix_diamond_values(tableobj, rid_to_index, coin_values, diamond_values)

        --保存赢金豆的数据
        tableobj.win_diamond_list = tableobj.win_diamond_list or { }
        for rid,rv in pairs(diamond_values) do
            tableobj.win_diamond_list[rid] = (tableobj.win_diamond_list[rid] or 0) + rv.value
        end
    end

    --更新当前金豆数
    for rid,rv in pairs(coin_values) do
        curr_seats_money[rid].coin = curr_seats_money[rid].coin + rv.value
    end

     --更新当前金豆数
    if diamond_values then
        for rid,rv in pairs(diamond_values) do
            curr_seats_money[rid].diamond = curr_seats_money[rid].diamond + rv.value
        end
    end

    filelog.print("-----------balance-----------",coin_values, diamond_values, curr_seats_money)
    
end

--[Comment]
--@ des 胡牌结算
--@ gameobj 游戏对象
--@ hu_seat 胡牌玩家座位
--
function GameLogic.settle_once_hupai(gameobj,hu_seat_indexs)
    local tableobj = gameobj.tableobj
    local is_zuanshi = false
    local base_score = tableobj.conf.score_diamond or 0
    local rids = { }
    local noticemsg = {
        money_change_list = { },
    }

    --初始分数
    local begin_scores = { }
    for _,s in pairs(tableobj.seats) do
        begin_scores[s.rid] = s.balance_score
    end
    
     --当前结算分数列表
    tableobj.cur_balance_score_list = tableobj.cur_balance_score_list or { }
    if tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI then
        is_zuanshi = true
    end
    
    for _,seat_index in pairs(hu_seat_indexs) do
        local tmpseat = tableobj.seats[seat_index]
        local win_seat_indexs = tmpseat.winhupai_fan_info

        tableobj.cur_balance_score_list[tmpseat.rid] = tableobj.cur_balance_score_list[tmpseat.rid] or { }
        local score_list = tableobj.cur_balance_score_list[tmpseat.rid] 

        local fan,total_fan = cardtool.calculate_fan(tmpseat.cards,tmpseat.di_cards,tmpseat.fan_types,tableobj.conf,tmpseat.hupai_card)
        tmpseat.fan_cnt = total_fan
        if tmpseat.fan_types[EMJHuPaiType.HUPAI_TYPE_DIAN_GANG_HUA] then --点杠花
            if tableobj.conf.is_dianganghua_as_zimo then
                local cnt = 0
                for _,seat in pairs(tableobj.seats) do
                    if GameLogic.is_ingame(gameobj, seat) and seat.rid ~= tmpseat.rid and not seat.is_hupai and not seat.is_giveup then
                        seat.curr_score = seat.curr_score - fan * base_score
                        cnt = cnt + 1
                        rids[seat.rid] = true
                        table.insert(win_seat_indexs,seat.index)
                        score_list[seat.index] = (score_list[seat.index] or 0) + fan * base_score
                    end
                end
                tmpseat.curr_score = tmpseat.curr_score + cnt * fan * base_score
            else
                local yinhu_seat = tableobj.seats[tmpseat.yinhu_seat_index]
                yinhu_seat.curr_score = yinhu_seat.curr_score - fan * base_score
                tmpseat.curr_score = tmpseat.curr_score +  fan * base_score
                rids[yinhu_seat.rid] = true
                table.insert(win_seat_indexs,yinhu_seat.index)
                score_list[yinhu_seat.index] = (score_list[yinhu_seat.index] or 0) + fan * base_score
            end
            rids[tmpseat.rid] = true
        elseif tmpseat.fan_types[EMJHuPaiType.HUPAI_TYPE_ZIMO] then     --自摸
            local cnt = 0
            for _,seat in pairs(tableobj.seats) do
                if GameLogic.is_ingame(gameobj, seat) and seat.rid ~= tmpseat.rid and not seat.is_hupai and not seat.is_giveup then
                    seat.curr_score = seat.curr_score - fan * base_score
                    cnt = cnt + 1
                    rids[seat.rid] = true
                    table.insert(win_seat_indexs,seat.index)
                    score_list[seat.index] = (score_list[seat.index] or 0) + fan * base_score
                end
            end
            tmpseat.curr_score = tmpseat.curr_score + cnt * fan * base_score
            rids[tmpseat.rid] = true
        else                                                            --点炮
            local yinhu_seat = tableobj.seats[tmpseat.yinhu_seat_index]
            yinhu_seat.curr_score = yinhu_seat.curr_score - fan * base_score
            tmpseat.curr_score = tmpseat.curr_score +  fan * base_score
            rids[yinhu_seat.rid] = true
            rids[tmpseat.rid] = true
            if tableobj.conf.is_hujiaozhuanyi then                      --呼叫转移
                if tmpseat.fan_types[EMJHuPaiType.HUPAI_TYPE_GANG_SHANG_PAO] then
                    GameLogic.hujiao_zhuanyi(gameobj,tmpseat,yinhu_seat)
                end
            end
            table.insert(win_seat_indexs,yinhu_seat.index)
            score_list[yinhu_seat.index] = (score_list[yinhu_seat.index] or 0) + fan * base_score
        end
    end

    --单次结算
    local end_scores = GameLogic.game_once_balance(gameobj)

    --通知客户端
    for _,seat in pairs(tableobj.seats) do
        local item = { rid = seat.rid, }
        if rids[seat.rid] then
            item.money_type = (is_zuanshi and EMoneyType.DIAMOND) or EMoneyType.SCORE
            local total_change = end_scores[seat.rid] - begin_scores[seat.rid]
            if is_zuanshi then
                item.final_value = seat.playerinfo.diamond + seat.balance_score
            elseif tableobj.table_type == EMJTableType.TABLE_TYPE_LIAN_XI_CHANG then
                item.money_type = EMoneyType.DOU or 4
                item.final_value = seat.playerinfo.dou + seat.balance_score
            elseif tableobj.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
                item.money_type = EMoneyType.COIN or 3
                item.final_value = seat.playerinfo.coin + seat.balance_score
                if item.final_value < 0 then    --不够扣
                    local ditem =  {
                        rid = seat.rid,
                        money_type = EMoneyType.DIAMOND,
                    }
                    
                    local begindiamond = seat.playerinfo.diamond
                    local begincoin = seat.playerinfo.coin + begin_scores[seat.rid]
                    if begincoin < 0 then
                        begindiamond = begindiamond + begincoin
                        begincoin = 0
                    end
                    ditem.change_value = total_change + begincoin
                    ditem.final_value = begindiamond + ditem.change_value
                    total_change = -begincoin
                    table.insert(noticemsg.money_change_list,ditem)
                    item.final_value = 0
                end
            else
                item.final_value = seat.total_score + seat.balance_score
            end
            item.change_value = total_change
            table.insert(noticemsg.money_change_list,item)
        end
    end
    tablelogic.sendmsg_to_alltableplayer(tableobj,"moneychangeN",noticemsg)
    
    return true
end

--[Comment]
--@ des 钻石场游戏中途结算
--@ gameobj 游戏对象
--
function GameLogic.game_half_diamond(gameobj,seat)
    local tableobj = gameobj.tableobj
    local rid_values = { }

    rid_values[seat.rid] = {}
    rid_values[seat.rid].rolename = seat.playerinfo.rolename
    rid_values[seat.rid].beginvalue = seat.playerinfo.diamond
    rid_values[seat.rid].value = seat.balance_score
    rid_values[seat.rid].endvalue = rid_values[seat.rid].beginvalue + rid_values[seat.rid].value
    seat.settle_score = seat.balance_score

    --修复扣费数据,防止扣成负数
    if rid_values[seat.rid].endvalue < 0 then
        rid_values[seat.rid].endvalue = 0
        rid_values[seat.rid].value = -rid_values[seat.rid].beginvalue
    end

    --通知gate去扣费
    local status = tablelogic.game_half_diamond(rid_values)
    if not status then
        filelog.sys_error("game half diamond failed!")
        return false
    else
        filelog.sys_info("game half diamond ok!")
    end

    return true
end

--[Comment]
--@ des 钻石场游戏结算
--@ gameobj 游戏对象
--
function GameLogic.game_balance_diamond(gameobj)
    local tableobj = gameobj.tableobj
    local noticemsg = { }
    noticemsg.money_change_list = { }

    local rid_values = { }
    local rid_to_index = { }
    for i,seat in pairs(tableobj.seats) do
        rid_values[seat.rid] = {}
        rid_values[seat.rid].rolename = seat.playerinfo.rolename
        rid_values[seat.rid].beginvalue = seat.playerinfo.diamond
        rid_values[seat.rid].value = seat.balance_score
        rid_values[seat.rid].endvalue = rid_values[seat.rid].beginvalue + rid_values[seat.rid].value
        rid_values[seat.rid].real_change = seat.real_change
        rid_values[seat.rid].level = seat.playerinfo.level
        rid_to_index[seat.rid] = i
        if seat.has_leave then
            if seat.balance_score == seat.settle_score then
                rid_values[seat.rid].had_half = true
            else
                rid_values[seat.rid].had_half = seat.settle_score   --已经结算的部分
                filelog.sys_error("need tuisui !!!", seat.rid, rid_values)
            end
            seat.settle_score = nil
        end
    end

    --修复扣费数据,防止扣成负数
    rid_values = GameLogic.fix_balance_values(rid_values)

    --通知gate去扣费
    local status,comment = tablelogic.game_balance_diamond(rid_values)
    if not status then
        filelog.sys_error("game balance diamond failed!")
        return false
    else
        filelog.sys_info("game balance diamond ok!")
    end
    tableobj.cur_table_tradeid = comment.table_tradeid or ""

    --扣费成功，修改数据
    for rid,rv in pairs(rid_values) do
        local item = { 
            rid = rid,
            money_type = EMoneyType.DIAMOND, --金钱类型：1得分 2钻石 3金币 4乐豆 5房卡
        }
        local tmpseat = tableobj.seats[rid_to_index[rid]]
        tmpseat.playerinfo.diamond = tmpseat.playerinfo.diamond + rv.value
        tmpseat.balance_score = rv.value
        item.final_value = rv.endvalue
        item.change_value = rv.value
        table.insert(noticemsg.money_change_list,item)
    end

    --通知客户端
    --tablelogic.sendmsg_to_alltableplayer(tableobj,"moneychangeN",noticemsg)
    
    return true
end

--[Comment]
--@ des 房卡场游戏结算
--@ gameobj 游戏对象
--@ seat 座位对象
--
function GameLogic.game_balance_fangka(gameobj)
    local tableobj = gameobj.tableobj
    local noticemsg = { }

    local rid_values = { }
    for i,seat in pairs(tableobj.seats) do
        rid_values[seat.rid] = {}
        rid_values[seat.rid].rolename = seat.playerinfo.rolename
        rid_values[seat.rid].beginvalue = 0
        rid_values[seat.rid].value = seat.total_score
        rid_values[seat.rid].endvalue = seat.total_score
    end
    
    local status = tablelogic.game_balance_fangka(rid_values)
    if not status then
        filelog.sys_error("game balance fangka failed!")
    else
        filelog.sys_info("game balance fangka ok.")
    end
end

--[Comment]
--@ des 练习场游戏结算
--@ gameobj 游戏对象
--@ seat 座位对象
--
function GameLogic.game_balance_dou(gameobj)
    local tableobj = gameobj.tableobj
    local noticemsg = { money_change_list = { } }
    for i,seat in pairs(tableobj.seats) do
        local item = { 
            rid = seat.rid,
            money_type = EMoneyType.DOU or 4, --金钱类型：1得分 2钻石 3金币 4乐豆 5房卡
        }
        seat.playerinfo.dou = seat.playerinfo.dou + seat.balance_score
        item.change_value = seat.balance_score
        item.final_value = seat.playerinfo.dou
        table.insert(noticemsg.money_change_list,item)
        if seat.is_robot and seat.playerinfo.dou < 30000 then
            seat.playerinfo.dou = 100000
        end
    end

    --通知客户端
    tablelogic.sendmsg_to_alltableplayer(tableobj,"moneychangeN",noticemsg)
end

--[Comment]
--@ des 金豆场游戏中途结算
--@ gameobj 游戏对象
--
function GameLogic.game_half_coin(gameobj,seat)
    local tableobj = gameobj.tableobj
    local rid_values = { }

    rid_values[seat.rid] = {}
    rid_values[seat.rid].rolename = seat.playerinfo.rolename
    rid_values[seat.rid].beginvalue = seat.playerinfo.coin
    rid_values[seat.rid].value = seat.balance_score
    rid_values[seat.rid].endvalue = rid_values[seat.rid].beginvalue + rid_values[seat.rid].value
    seat.settle_score = seat.balance_score

    --修复扣费数据,防止扣成负数
    if rid_values[seat.rid].endvalue < 0 then
        rid_values[seat.rid].endvalue = 0
        rid_values[seat.rid].value = -rid_values[seat.rid].beginvalue
    end

    --通知gate去扣费
    local ridvalues_list = { coin = rid_values}
    local status = tablelogic.game_half_coin(ridvalues_list)
    if not status then
        filelog.sys_error("game half coin failed!")
        return false
    else
        filelog.sys_info("game half coin ok!")
    end

    return true
end

--[Comment]
--@ des 修复金豆结算数据
--
function GameLogic.fix_diamond_values(tableobj, rid_to_index, coin_values, diamond_values)
     local cur_balance_score_list = tableobj.back_balance_score_list or { }

     local rid_values = tabletool.deepcopy(diamond_values)
     for rid,rv in pairs(rid_values) do
        local i = rid_to_index[rid]
        local seat = tableobj.seats[i]
        local total_win = -(rv.value + coin_values[rid].value)
        local over_score = -rv.value
        if total_win > 0 then
            local total_value = 0
            local win_rid = nil
            for _,otherseat in pairs(tableobj.seats) do
                if otherseat.rid ~= seat.rid then
                    local score_list = cur_balance_score_list[otherseat.rid]
                    if score_list and score_list[seat.index] then
                        local p = score_list[seat.index] / total_win
                        local win_diamond = math.floor(over_score * p)
                        if not diamond_values[otherseat.rid] then
                            diamond_values[otherseat.rid] = {
                                beginvalue = 0,
                                value = 0,
                                endvalue = 0,
                            }
                        end
                        diamond_values[otherseat.rid].value = diamond_values[otherseat.rid].value + win_diamond
                        total_value = total_value + win_diamond
                        win_rid = otherseat.rid
                    end
                end
            end

            if total_value ~= over_score and win_rid then
                local sub = over_score - total_value
                local rv = diamond_values[win_rid]
                rv.value = rv.value + sub
            end
        end
    end

    --修复金豆数据
    for rid,rv in pairs(diamond_values) do
        if rv.value > 0 then
            local crv = coin_values[rid]
            crv.value = crv.value - rv.value
            crv.endvalue = crv.beginvalue + crv.value
        end
    end
    
    return true
end

--[Comment]
--@ des 金币场游戏结算
--@ gameobj 游戏对象
--@ seat 座位对象
--
function GameLogic.game_balance_coin(gameobj)
    local tableobj = gameobj.tableobj
    local noticemsg = { }
    noticemsg.money_change_list = { }

    for _,s in pairs(tableobj.seats) do
        print("1---seat:--",s.index, s.rid, s.balance_score)
    end

    local ridvalues_list = { }
    local coin_values = { }
    local diamond_values = nil
    local rid_to_index = { }
    for i,seat in pairs(tableobj.seats) do
        coin_values[seat.rid] = {}
        coin_values[seat.rid].rolename = seat.playerinfo.rolename
        coin_values[seat.rid].beginvalue = seat.playerinfo.coin
        coin_values[seat.rid].value = seat.balance_score
        coin_values[seat.rid].endvalue = coin_values[seat.rid].beginvalue + coin_values[seat.rid].value
        rid_to_index[seat.rid] = i
        --金豆不够，扣金豆
        if coin_values[seat.rid].endvalue < 0 then
            diamond_values = diamond_values or { }
            diamond_values[seat.rid] = { }
            diamond_values[seat.rid].rolename = seat.playerinfo.rolename
            diamond_values[seat.rid].beginvalue = seat.playerinfo.diamond
            diamond_values[seat.rid].value = coin_values[seat.rid].endvalue
            diamond_values[seat.rid].endvalue = diamond_values[seat.rid].beginvalue + diamond_values[seat.rid].value
            coin_values[seat.rid].endvalue = 0
            coin_values[seat.rid].value = -seat.playerinfo.coin
        end
        if seat.has_leave then
            if seat.balance_score == seat.settle_score then
                coin_values[seat.rid].had_half = true
                if diamond_values and diamond_values[seat.rid] then
                    diamond_values[seat.rid].had_half = true
                end
            else
                coin_values[seat.rid].had_half = seat.settle_score
                filelog.sys_error("need tuisui !!!", seat.rid, coin_values)
            end
            seat.settle_score = nil
        end
    end

    filelog.print("----rid_values----1---",coin_values, diamond_values)

    --修复金豆结算
    if diamond_values then
        tableobj.win_diamond_list = tableobj.win_diamond_list or { }
        for rid,score in pairs(tableobj.win_diamond_list) do
            if score > 0 then
                local i = rid_to_index[rid]
                local curseat = tableobj.seats[i]
                diamond_values[rid] = diamond_values[rid] or { }
                diamond_values[rid].rolename = curseat.playerinfo.rolename
                diamond_values[rid].beginvalue = curseat.playerinfo.diamond
                diamond_values[rid].value = (diamond_values[rid].value or 0) + score
                diamond_values[rid].endvalue = diamond_values[rid].beginvalue + diamond_values[rid].value
            end
        end

        --修复金豆数据
        for rid,rv in pairs(diamond_values) do
            if rv.value > 0 then
                local crv = coin_values[rid]
                crv.value = crv.value - rv.value
                crv.endvalue = crv.beginvalue + crv.value
            end
        end
    end

    filelog.print("----rid_values----2---",coin_values, diamond_values)
    
    --修复扣费数据,防止扣成负数
    coin_values = GameLogic.fix_balance_values(coin_values)
    diamond_values = GameLogic.fix_balance_values(diamond_values)
    
    filelog.print("----rid_values----3---",coin_values, diamond_values)

    --通知gate去扣费
    local ridvalues_list = { coin = coin_values, diamond = diamond_values}
    local status,comment = tablelogic.game_balance_coin(ridvalues_list)
    if not status then
        filelog.sys_error("game balance coin failed!")
        return false
    else
        filelog.sys_info("game balance coin ok!")
    end
    tableobj.cur_table_tradeid = comment.table_tradeid or ""

    --扣费成功，修改数据
    for rid,rv in pairs(coin_values) do
        local item = { 
            rid = rid,
            money_type = EMoneyType.COIN or 3, --金钱类型：1得分 2钻石 3金币 4乐豆 5房卡
        }
        local tmpseat = tableobj.seats[rid_to_index[rid]]
        tmpseat.playerinfo.coin = tmpseat.playerinfo.coin + rv.value
        tmpseat.total_score = tmpseat.total_score - tmpseat.balance_score + rv.value
        tmpseat.balance_score = rv.value
        item.final_value = rv.endvalue
        item.change_value = rv.value
        table.insert(noticemsg.money_change_list,item)
    end

    --扣费成功，修改数据
    diamond_values = diamond_values or { }
    for rid,rv in pairs(diamond_values) do
        local item = { 
            rid = rid,
            money_type = EMoneyType.DIAMOND or 2, --金钱类型：1得分 2钻石 3金币 4乐豆 5房卡
        }
        local tmpseat = tableobj.seats[rid_to_index[rid]]
        tmpseat.playerinfo.diamond = tmpseat.playerinfo.diamond + rv.value
        tmpseat.total_score = tmpseat.total_score + rv.value
        tmpseat.balance_score = tmpseat.balance_score + rv.value
        item.final_value = rv.endvalue
        item.change_value = rv.value
        table.insert(noticemsg.money_change_list,item)
    end

    --通知客户端
    --tablelogic.sendmsg_to_alltableplayer(tableobj,"moneychangeN",noticemsg)
    
    return true
end

---------------------------------------------------------------------
---
--

--[Comment]
--@ des 大叫,牌局结束时，未听牌玩家赔给听牌玩家可胡最大番
--@ gameobj 游戏对象
--@ seat 玩家座位
--
function GameLogic.da_jiao(gameobj,seat)
    local tableobj = gameobj.tableobj
    if seat == nil then
        return
    end

    --当前结算分数列表
    tableobj.cur_balance_score_list = tableobj.cur_balance_score_list or { }

    local base_score = tableobj.conf.score_diamond or 0
    local max_fan = tableobj.conf.max_multi_num or 8
    local total_score = 0
    for _,tmpseat in pairs(tableobj.seats) do
        if tmpseat.rid ~= seat.rid and not tmpseat.is_hupai and not tmpseat.is_giveup then
            local isTing,ting_cards = cardtool.check_is_tingpai(tmpseat.cards,true,tmpseat.que_cardcolor,tableobj.is_7zhang)
            if isTing then
                local di_values = { }
                for _,item in pairs(tmpseat.di_cards) do
                    table.insert(di_values,item.card)
                    table.insert(di_values,item.card)
                    table.insert(di_values,item.card)
                    if item.gang_peng_type ~= EMJGangPengType.GANGPENG_TYPE_PENG then
                        table.insert(di_values,item.card)
                    end
                end
                
                local cur_max_fan = 0
                local cur_max_fans = nil
                local round_num = GameLogic.get_round_num(gameobj)
                for _,v in pairs(ting_cards) do
                    local ret,fan_types = cardtool.check_hu(tmpseat.cards,di_values,v,tmpseat.is_banker,round_num,tmpseat.que_cardcolor,tableobj.is_7zhang)
                    if ret then
                        local gou_num = cardtool.get_gou_num(tmpseat.cards,tmpseat.di_cards,fan_types)
                        if cur_max_fan < fan_types[fan_types.max_type] + gou_num then
                            cur_max_fan = fan_types[fan_types.max_type] + gou_num
                            cur_max_fans = fan_types
                        end
                    else
                        filelog.print("-----error",tmpseat.index)
                    end
                end
                if cur_max_fan > max_fan then
                    cur_max_fan = max_fan
                end
                
                filelog.print(tmpseat.index,"may max fan:",cur_max_fan,cur_max_fans)
                tmpseat.curr_score = tmpseat.curr_score + cur_max_fan * base_score
                total_score = total_score + cur_max_fan * base_score

                tableobj.cur_balance_score_list[tmpseat.rid] = tableobj.cur_balance_score_list[tmpseat.rid] or { }
                local score_list = tableobj.cur_balance_score_list[tmpseat.rid] 
                score_list[seat.index] = (score_list[seat.index] or 0) + cur_max_fan * base_score
            end
        end
    end

    seat.curr_score = seat.curr_score - total_score
end

--[Comment]
--@ des 花猪,牌局结束时，花猪玩家赔给非花猪玩家封顶倍数
--@ gameobj 游戏对象
--@ seat 玩家座位
--
function GameLogic.hua_zhu(gameobj,seat)
    local tableobj = gameobj.tableobj
    if seat == nil then
        return
    end

    --当前结算分数列表
    tableobj.cur_balance_score_list = tableobj.cur_balance_score_list or { }

    local base_score = tableobj.conf.score_diamond
    local max_fan = tableobj.conf.max_multi_num
    local cnt = 0
    for _,tmpseat in pairs(tableobj.seats) do
        if tmpseat.rid ~= seat.rid and not tmpseat.is_gameend and not cardtool.is_hua_zhu(tmpseat.cards) then
            tableobj.cur_balance_score_list[tmpseat.rid] = tableobj.cur_balance_score_list[tmpseat.rid] or { }
            local score_list = tableobj.cur_balance_score_list[tmpseat.rid] 
            score_list[seat.index] = (score_list[seat.index] or 0) + max_fan * base_score

            tmpseat.curr_score = tmpseat.curr_score + max_fan * base_score
            cnt = cnt + 1
        end
    end
    seat.curr_score = seat.curr_score - cnt * max_fan * base_score
end

--[Comment]
--@ des 退税,牌局结束时，未听牌玩家要退还杠牌所得
--@ gameobj 游戏对象
--@ seat 玩家座位
--
function GameLogic.tui_sui(gameobj,seat)
    local tableobj = gameobj.tableobj
    if seat == nil then
        return
    end

    local is_tuisui = false
    tableobj.gangpai_score_list = tableobj.gangpai_score_list or {}

    local score_list = tableobj.gangpai_score_list[seat.rid] or { }
    for index,score in pairs(score_list) do
        is_tuisui = true
        local tmpseat = tableobj.seats[index]
        tmpseat.curr_score = tmpseat.curr_score - score
    end
    tableobj.gangpai_score_list[seat.rid] = nil
    
    return is_tuisui
end

--[Comment]
--@ des 呼叫转移,杠上炮时，杠牌玩家需将所有杠牌所得转移给被点炮玩家
--@ gameobj 游戏对象
--
function GameLogic.hujiao_zhuanyi(gameobj,hupai_seat,yinhu_seat)
    local tableobj = gameobj.tableobj
    local is_hujiao = false

    tableobj.cur_balance_score_list = tableobj.cur_balance_score_list or { }
    tableobj.cur_balance_score_list[hupai_seat.rid] = tableobj.cur_balance_score_list[hupai_seat.rid] or { }
    if not tableobj.cur_balance_score_list[yinhu_seat.rid] then
        return 
    end

    local win_score_list = tableobj.cur_balance_score_list[hupai_seat.rid] 
    local lose_score_list = tableobj.cur_balance_score_list[yinhu_seat.rid]
    for index,score in pairs(lose_score_list) do
        win_score_list[index] = (win_score_list[index] or 0) + score
        hupai_seat.curr_score = hupai_seat.curr_score + score
        yinhu_seat.curr_score = yinhu_seat.curr_score - score
        is_hujiao = true
    end
    tableobj.cur_balance_score_list[yinhu_seat.rid] = nil

    --通知呼叫转移
    if is_hujiao then
        local msg = {
            rid = yinhu_seat.rid,
            seat_index = yinhu_seat.index,
            move_rid = hupai_seat.rid,
            move_seat_index = hupai_seat.index,
        }
        tablelogic.sendmsg_to_alltableplayer(tableobj,"hujiaozhuanyiN",msg)
    end
end

--[Comment]
--@ des 修复结算数据,保证数据的正确性
--
function GameLogic.fix_balance_values(rid_values)
    if not rid_values then
        return
    end

    local back_values = tabletool.deepcopy(rid_values)
    local negative_values = { }
    local positive_values = { }
    local total_win_value = 0
    local total_lost_value = 0
    for rid,values in pairs(rid_values) do
        if values.endvalue < 0 then
            table.insert(negative_values,rid)
            total_lost_value = total_lost_value + (-values.endvalue)
            values.endvalue = 0
            values.value = -values.beginvalue
        elseif values.endvalue > 0 and values.value > 0 then
            table.insert(positive_values,rid)
            total_win_value = total_win_value + values.value
        end
    end
    
    if total_lost_value <= 0 or total_win_value <= 0 then
        return rid_values
    end

    local total_value = 0
    for i = 1,#positive_values do
        local rid = positive_values[i]
        local values = rid_values[rid]
        local tmp = math.floor(values.value / total_win_value) * total_lost_value
        if i == #positive_values then
            tmp = total_lost_value - total_value
        end
        values.value = values.value - tmp 
        if values.value < 0 then
            tmp = tmp + values.value
            values.value = 0
        end
        values.endvalue = values.value + values.beginvalue
        total_value = total_value + tmp
    end
    
    if total_value == total_lost_value then
        return rid_values
    end

    local tmp = total_lost_value - total_value
    if total_value < total_lost_value then
        for _,rid in pairs(positive_values) do
            local values = rid_values[rid]
            if values.value > 0 then
                if values.value >= tmp then
                    values.value = values.value - tmp
                    values.endvalue = values.value + values.beginvalue
                    break
                else
                    tmp = tmp - values.value
                    values.value = 0
                    values.endvalue = values.beginvalue
                end
            end
        end
        if tmp ~= 0 then
            return back_values
        end
    else
        filelog.print("fix balance values failed!")
        return back_values
    end 

    return rid_values
end

--[Comment]
--检测赢上限
--超出上限，按 上限值/当前值 按比例计算
--
function GameLogic.check_limit_of_winorlose(tableobj)
    local limit_diamonds = tableobj.init_diamond_list
    local win_diamond_limits = tableobj.win_diamond_limits
    local cur_balance_score_list = tableobj.cur_balance_score_list or { }
    local is_ypdx = false   --是否一炮多响

    if tableobj.ypdx_seat_index and tableobj.ypdx_seat_index ~= 0 then
        is_ypdx = true
    end

    filelog.print("------------------1-------------",tableobj.cur_balance_score_list)

    --又输又赢，计算最终输赢
    for _,seat in pairs(tableobj.seats) do
        if not seat.is_gameend then
            local win_scorelist = cur_balance_score_list[seat.rid]
            if win_scorelist then
                for rid,score_list in pairs(cur_balance_score_list) do
                    if rid ~= seat.rid and score_list[seat.index] then
                        local score = score_list[seat.index]
                        for i,val in pairs(win_scorelist) do
                            if val >= score then
                                win_scorelist[i] = val - score
                                score_list[seat.index] = nil
                                if tableobj.seats[i].rid ~= rid then
                                    score_list[i] = (score_list[i] or 0) + score
                                end
                                if win_scorelist[i] == 0 then
                                    win_scorelist[i] = nil
                                end
                                break
                            else
                                score_list[seat.index] = score_list[seat.index] - val
                                if tableobj.seats[i].rid ~= rid then
                                    score_list[i] = (score_list[i] or 0) + val
                                end
                                score = score_list[seat.index]
                                win_scorelist[i] = nil
                            end
                        end
                    end
                end
            end
        end
    end

    filelog.print("------------------2-------------",tableobj.cur_balance_score_list)

     --检测输上限
    for _,seat in pairs(tableobj.seats) do
        if limit_diamonds[seat.rid] + seat.curr_score < 0 then
            --按比例扣赢家
            local total_win = 0
            local win_list = { }
            local win_seat_list = { }
            local lose_score = limit_diamonds[seat.rid]
            for _,otherseat in pairs(tableobj.seats) do
                if otherseat.rid ~= seat.rid  then
                    local score_list = cur_balance_score_list[otherseat.rid]
                    if score_list and score_list[seat.index] then
                        total_win = total_win + score_list[seat.index]
                        table.insert(win_list,otherseat.rid)
                        win_seat_list[otherseat.index] = score_list[seat.index]
                    end
                end
            end
            
            --赢家按比例赢输家实际输的分数
            local total_score = 0
            if total_win > 0 then
                for _,rid in pairs(win_list) do
                    local score_list = cur_balance_score_list[rid]
                    local p = score_list[seat.index] / total_win
                    local real_winscore = math.floor(p * lose_score)
                    score_list[seat.index] = real_winscore
                    total_score = total_score + real_winscore
                end
            end
            
            --输家还有剩余，给第一个赢的玩家
            if total_score < lose_score then
                for _,rid in pairs(win_list) do
                    local score_list = cur_balance_score_list[rid]
                    score_list[seat.index] = score_list[seat.index] + (lose_score - total_score)
                    break
                end
            end

            --重新计算座位得分
            for seat_index,init_score in pairs(win_seat_list) do
                local cur_seat = tableobj.seats[seat_index]
                local score_list = cur_balance_score_list[cur_seat.rid] or { }
                cur_seat.curr_score = cur_seat.curr_score - (init_score - (score_list[seat.index] or 0) )
            end
            seat.curr_score = -limit_diamonds[seat.rid]
        end
    end

    filelog.print("------------------3-------------",tableobj.cur_balance_score_list)

    --检测赢上限,已经检测输上限，不存在不够扣
    for _,seat in pairs(tableobj.seats) do
        if seat.curr_score > win_diamond_limits[seat.rid] then  
            local max_win_score = win_diamond_limits[seat.rid]
            local curr_score = seat.curr_score
            local p = max_win_score / curr_score    --（得分上限 / 总得分),总得分包括杠牌分和胡牌分
            local win_score = 0
            local score_list = cur_balance_score_list[seat.rid] or { }
            for index,score in pairs(score_list) do
                local lost_seat = tableobj.seats[index]
                local real_score = math.floor(p * score)
                local sub_score = score - real_score
                lost_seat.curr_score = lost_seat.curr_score + sub_score
                win_score = win_score + real_score
                score_list[index] = real_score
            end
            seat.curr_score = win_score
        end
    end

    filelog.print("------------------4-------------",tableobj.cur_balance_score_list)
    
end

--[Comment]
--检测是否输光
--
function GameLogic.check_is_loseall(tableobj)
    if tableobj.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then
        return false
    end

    local limit_diamonds = tableobj.init_diamond_list
    local loseall_list = { }

    for _,seat in pairs(tableobj.seats) do
        if not seat.is_hupai and not seat.is_giveup 
        and limit_diamonds[seat.rid] <= 0 then
            table.insert(loseall_list,seat.index)
        end
    end
    
    if #loseall_list > 0 then
        --通知客户端，玩家钱不够
        for _,index in pairs(loseall_list) do
            local curseat = tableobj.seats[index]
            local noticemsg = {
                rid = curseat.rid,
                seat_index = curseat.index,
                table_index = tableobj.index,
            }
            tablelogic.sendmsg_to_alltableplayer(tableobj, "notenoughmoneyN", noticemsg)
        end
    
        --等待5s，若未充值则自动认输
        tableobj.timer_id = timer.settimer(5 * 100, "wait_charge")
        tableobj.state = EMJTableState.TABLE_STATE_WAIT_CHARGE
        return true
    end
    
    return false
end

--[Comment]
--@ des 处理玩家托管
--@ gameobj 游戏对象
--@ seat 座位对象
--
function GameLogic.dotuoguan(gameobj, seat)
	local tableobj = gameobj.tableobj

    if tableobj.action_player_list == nil then
        return 
    end

    local player_action = tableobj.action_player_list[seat.rid]
	if player_action == nil or player_action.action_state ~= EMJActionState.NODO then
		return
	end

	local max_action_type = 0
	for _, action_type in pairs(player_action.wait_action_types) do
		if max_action_type < action_type then
			max_action_type = action_type
		end
	end

	local requestmsg = {
		action_type = max_action_type,
		card = 0,
	}	

	if requestmsg.action_type == EMJActionType.MJ_ACTION_TYPE_HUPAI  then   --胡牌不需要其他操作

    elseif requestmsg.action_type == EMJActionType.MJ_ACTION_TYPE_PENG then   --碰  
        if seat.is_robot then
            local is_good = cardtool.check_is_good_peng(seat.cards,tableobj.chu_mo_pai_card,seat.que_cardcolor)   --检测碰牌是否划算
            if not is_good then
                requestmsg.action_type = EMJActionType.MJ_ACTION_TYPE_GUO
            end
        elseif not seat.is_disconnected then
            requestmsg.action_type = EMJActionType.MJ_ACTION_TYPE_GUO
        end
	elseif requestmsg.action_type == EMJActionType.MJ_ACTION_TYPE_BAGANG then   --添杠
		local is_find = false
		for _, card in pairs(seat.cards) do
			for _, gangpengitem in pairs(seat.di_cards) do
				if gangpengitem.gang_peng_type == EMJGangPengType.GANGPENG_TYPE_PENG
					and gangpengitem.card == card then
					requestmsg.card = card
					is_find = true
					break			
				end
			end
			if is_find then
				break
			end
		end
	elseif requestmsg.action_type == EMJActionType.MJ_ACTION_TYPE_ZHIGANG then  --明杠
		requestmsg.card = tableobj.chu_mo_pai_card
	elseif requestmsg.action_type == EMJActionType.MJ_ACTION_TYPE_ANGANG then   --暗杠
		local gang_card = 0
		local gang_cards = cardtool.get_gang_cards(seat.cards,seat.que_cardcolor)
		if #gang_cards > 0 then
			gang_card = gang_cards[1]
		else
			return
		end
		requestmsg.card = gang_card
	elseif requestmsg.action_type == EMJActionType.MJ_ACTION_TYPE_CHUPAI        --出牌
    or requestmsg.action_type == EMJActionType.MJ_ACTION_TYPE_GANG_CHUPAI then
        if seat.is_robot then
            local all_outcards = {}
            local all_dicards = {}
            for i,tmpseat in pairs(tableobj.seats) do
                if GameLogic.is_ingame(gameobj, tmpseat) then
                    all_outcards[i] = tmpseat.out_cards or { }
                    all_dicards[i] = tmpseat.di_cards or { }
                end
            end
            requestmsg.card = cardtool.get_robot_chupai(seat.cards,all_outcards,all_dicards,seat.que_cardcolor)
        else
            requestmsg.card = cardtool.get_tuoguan_chupai(seat.cards,seat.que_cardcolor)
        end
	end

	return tablelogic.doaction(tableobj, seat.rid,requestmsg, seat)
end

---------------------------------------------------------

return GameLogic

---游戏逻辑----